我正在修改和清理前同事的代碼。我創建了一個聯合,通過他設計的 UART 傳輸協議來簡化訊息的“決議”和“構造”。
示例訊息:!cx:000:2047
第一個字符表示引數(由第二個和第三個字符定義,在本例中cx為 )是否應該設定(!)或回傳(?)給訊息的發送者。如果需要,訊息 ( ) 的地址部分000定義陣列中的索引,指定的值(在本例中2047)應寫入該索引。命令、地址和值使用:字符分隔。
我本來可以使用strtok()分隔字符來分隔訊息,但接收緩沖區的大小固定為 12 個字符,發送函式確保訊息的格式正確,我發現這種方法最容易閱讀和理解。
但是現在,我已經看到了這個帖子,我不確定以下聯合是否合法:
typedef union UartMessage
{
char msg[12];
struct
{
char dir; //[0]: set/get
char param[2]; //[1-2]: parameter to set/get
char separator1; //[3]: ':' separator
char addr[3]; //[4-6]: memory array index (used for current and speed arrays)
char separator2; //[7]: ':' separator
char value[4]; //[8-11]: value to set
};
} uartMsg_t;
uj5u.com熱心網友回復:
在“聯合型別雙關語”方面,C 和 C 是不同的。在 C 中,我們可能會寫入一個聯合成員并從另一個成員讀取,然后將二進制值轉換為新型別。假設沒有對齊問題并且新型別可以基于值來表示,這在 C 中是明確定義的1)。在 C 中執行相同操作會呼叫未定義的行為。
至于union用C編譯時你的作品是否有效,這取決于對齊方式。僅由成員(或它們的陣列)組成的結構/聯合char不應該有任何填充,盡管理論上編譯器可以自由插入它。最佳實踐涉及進行編譯時檢查以確保這不是問題:
_Static_assert(sizeof(uartMsg_t) == sizeof((uartMsg_t){0}.msg),
"Padding detected!");
在其他情況下,當您確實有填充時,您可能必須使用非標準#pragma pack或類似方法顯式禁用它。使用結構表示資料協議的最大可移植程式需要呼叫顯式的序列化/反序列化例程(可移植性高于性能)。
1) 來源:C17 6.5.2.3 注 97),C17 6.2.6
uj5u.com熱心網友回復:
自 C11 添加匿名結構以來,它是合法的。
但是,如果嵌入式結構中沒有引入額外的填充,我建議添加一個斷言。
_Static_assert(offsetof(uartMsg_t, value[4]) == 12, "extra padding");
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/485090.html
標籤:C
