在實際的軟體開發專案中,多模組協作是常態。不同模組之間若要實現高效、可靠的通信,必須遵循共同的訊息規範——這就是「通信協議」。本文將透過實際 C 語言程式碼範例,深入淺出地講解如何定義協議結構、實作訊息解析邏輯,並完整示範單元測試的設計與執行流程,為嵌入式與系統級開發工程師提供實戰參考。
簡單來說,協議就是模組之間「說話」的共同語言。一條完整的訊息通常由訊息頭和訊息體兩部分組成:

圖1 一條完整的訊息結構示意圖
在 C 語言中,我們習慣使用 struct 結構體來映射協議格式,方便記憶體對齊與直接存取。
單元測試是程式碼交付前的關鍵防線。它針對單一函數,驗證「給定特定輸入,是否產生預期輸出」。測試過程可視為一個「灰盒」:輸入測試資料,觀察輸出結果,不關心內部實現細節。

圖2 單元測試示意圖
完整的測試用例應包含:測試目的、預置條件、測試步驟、預期結果、通過準則及測試工具等要素。
本範例定義了一個用戶請求訊息 UserReqMsg_T,包含 4 個保留字段的訊息頭,以及 5 個業務字段的訊息體:
// 訊息頭結構
typedef struct {
UINT16 iReserve1;
UINT16 iReserve2;
UINT16 iReserve3;
UINT16 iReserve4;
} MsgHead_T;
// 完整訊息結構體
typedef struct {
MsgHead_T MsgHead; // 訊息頭
UINT32 iOperType; // 操作類型 (僅允許 1 或 2)
UINT8 szUserNumber[30]; // 用戶號碼
UINT8 szOperTime[20]; // 操作時間 (格式: yyyymmdd)
UINT32 iReserve1; // 保留字段1
UINT8 szReserve2[50]; // 保留字段2
} UserReqMsg_T;
設計亮點: 預留字段是為了未來協議升級擴展而保留的「彈性空間」。當新增業務欄位時,無需修改協議結構版本,直接復用保留字段即可,極大降低了維護成本與相容性風險。
程式主流程:初始化訊息頭 → 從標準輸入讀取業務字段 → 調用驗證函數 ProcUserReqMsg → 根據返回值輸出結果或錯誤資訊。
INT32 ProcUserReqMsg(UserReqMsg_T *ptUserReqMsg) {
// 1. 空指標防護
if (ptUserReqMsg == NULL) return -1;
// 2. 業務規則校驗
if ((ptUserReqMsg->iOperType != 1) && (ptUserReqMsg->iOperType != 2)) return -2; // 操作類型非法
if (strlen(ptUserReqMsg->szUserNumber) != 8) return -3; // 號碼長度異常
if (strlen(ptUserReqMsg->szOperTime) != 8) return -4; // 時間格式異常
return 0; // 校驗通過
}
關鍵細節:使用 strncpy 替代 strcpy 防止緩衝區溢出;參數傳遞採用指標傳址,避免結構體大量複製開銷。
測試策略遵循「正常路徑全覆蓋、異常路徑全攔截」原則:

圖3 操作類型為1的正常執行情況

圖4 操作類型為2的正常執行情況

圖5 操作類型為3的異常執行情況

圖6 用戶號碼為9位的異常執行情況

圖7 操作時間為9位的異常執行情況
掌握協議設計與單元測試,是從「寫出能跑的代碼」進階為「交付可維護產品」的必經之路。