簡體   English   中英

uint32_t和uint8_t [4]的C聯合是否總是在小端架構上以相同的方式映射?

[英]Will a C union of uint32_t and uint8_t[4] will always map the same way on little endian architectures?

uint32_t和uint8_t [4]的C聯合是否總是在小端架構上以相同的方式映射?

例如

union {
    uint32_t double_word;
    uint8_t octets[4];
} u;

u.double_word = 0x12345678;

總是導致:

u.octets[0] == 0x78
u.octets[1] == 0x56
u.octets[2] == 0x34
u.octets[3] == 0x12

或者這是未定義的行為?

TL; DR:是的,代碼很好。

如上所述,它包含依賴於endianess的實現定義的行為,但除此之外,行為是明確定義的,代碼是可移植的(在小端機器之間)。


詳細解答:

一件重要的事情是保證陣列的分配順序,C11 6.2.5 / 20:

數組類型描述了具有特定成員對象類型的連續分配的非空對象集,稱為元素類型。

這意味着4 uint8_t的數組保證遵循uint32_t的分配順序,這在小端系統上首先表示最低有效字節。

理論上,編譯器可以自由地在聯合的末尾拋出任何填充(C11 6.7.2.1/17),但這不應該影響數據表示。 如果你想要迂腐地防止這種情況 - 或者更相關的是,你希望防止以后添加更多成員的問題 - 你可以添加一個編譯時斷言:

typedef union {
    uint32_t double_word;
    uint8_t octets[4];
} u;

_Static_assert(sizeof(u) == sizeof(uint32_t), "union u: Padding detected");

至於uintn_t類型的表示,它保證是2的補碼(在有符號類型的情況下)沒有填充位(C11 7.20.1.1)。

最后,關於是否通過聯合“打字”的問題是允許的還是未定義的行為,這在C11 6.5.2.3中有點模糊:

后綴表達式后跟. 運算符和標識符指定結構或聯合對象的成員。 該值是指定成員的值, 95)如果第一個表達式是左值,則它是左值。

(非規范性)說明95提供澄清的地方:

如果用於讀取union對象內容的成員與上次用於在對象中存儲值的成員不同,則將值的對象表示的相應部分重新解釋為新類型中的對象表示形式在6.2.6中描述(一個過程有時被稱為''punning'')。 這可能是陷阱表示。

由於我們已經排除了填充位,陷阱表示不是問題。

在實際上具有這兩種類型的平台上, C11§7.20.1.1p2為您提供了所有必需的保證(假設您知道字節順序):

typedef名稱uintN_t指定一個寬度為N且沒有填充位的無符號整數類型。 因此, uint24_t表示這樣的無符號整數類型,其寬度恰好為24位。

這就足夠了,因為沒有少於8位的字節,因此自動使用uint8_t意味着一個字節恰好有8位。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM