聯盟

2012-01-19 253 views
3

如果我在以下代碼爲8位處理器:聯盟

typedef union 
{ 
unsigned long longn ; 
unsigned char chars[4]; 
} longbytes; 

longbytes.chars[0]總是要的longbytes.longn最低字節,或者它依賴在字節順序/編譯器/平臺/目標/運氣等?我已經查看了我編寫的代碼的反彙編,這就是我的具體情況,但我很好奇這個代碼是否可移植。

回答

7

有幾個原因,這是不可移植:

  • 這取決於你的平臺(或編譯器)強制執行字節順序哪個字節的第一個寫的,所以你不能指望chars[0]解決最低字節
  • unsigned long不能保證完全一樣,只要4字符,所以根據不同的平臺上,你甚至可能沒有得到完整的long(或的sizeof(long)可能會更小,然後4和你繼續讀下去,但是這是不可能的8位處理器至少。
  • 閱讀不同的工會成員,然後你寫信給一般是不可移植的,它是實現定義的行爲。其原因基本上是兩個問題的結合。

因此,所有代碼都不是可移植的。

+0

在n1570,6.5.2.3,腳註95寫着「如果用於讀取聯合對象的內容的成員不是與最後用於在對象中存儲值的成員相同,該值的對象表示形式的適當部分將重新解釋爲新類型中的對象表示形式,如6.2.6中所述(有時稱爲「類型剔除」 ''),這可能是陷阱表示。「所以它現在是半定義的。 –

+0

我認爲該標準對'unsigned char'數組的類型竄改做了一個特殊的例外。 –

+0

@DanielFischer:好吧,所以它實際上是實現定義的。將修復我的答案 – Grizzly

1

這取決於平臺如何在內部存儲long。寫入一個工會的一個元素,然後從另一個元素讀取是不可移植的。

1

union這個union數據結構是可移植的,只要您不寫入其中的一部分並從另一部分讀取而導致未定義的行爲。具體而言,寫入unsigned long和從unsigned char[4]讀取或反之亦然是未定義的行爲。

4

一般來說,如果您需要關心字節序排序問題,那麼您需要解決問題(例如,使用輪班和掩碼,或序列化/反序列化)。

例如,而不是工會也許你應該這樣做:

uint32_t pack(uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3) { 
    long result; 

    result = byte0; 
    result |= byte1 << 8; 
    result |= byte2 << 16; 
    result |= byte3 << 24; 
    return result; 
} 

uint8_t unpack(int byteNumber, uint32_t value) { 
    return (value >> (byteNumber * 8)); 
} 
+0

我試圖直接訪問字節的原因是因爲當我這樣做時,結果代碼將數據中的長和OR的四個字節連續四次移位,這對我的應用程序來說過於緩慢。它在整數方面效果更好(它將數據字節放在適當的寄存器中,但仍然有不必要的或),但它完全失敗並且很長。 – KNfLrPn