2011-11-15 40 views
0

我正在使用一個本地無符號長變量作爲緩衝區,用於在其中包含兩個無符號短變量。從我對C++的知識來看,它應該是一個有效的方法。我用這種方法在一次無符號短內部多次存儲2個unsigned char,沒有任何問題。不幸的是,當在不同的架構上使用它時,它的反應很奇怪。它似乎在第二次分配後更新該值。 (溢出)案例就是爲了演示它。任何人都可以闡明爲什麼它會這樣反應嗎?類型轉換後的值不正確

unsigned long dwTest = 0xFFEEDDCC; 

printf("sizeof(unsigned short) = %d\n", sizeof(unsigned short)); 
printf("dwTest = %08X\n", dwTest); 

//Address + values 
printf("Addresses + Values: %08X <- %08X, %08X <- %08X\n", (DWORD)(&((unsigned short*)&dwTest)[0]), (((unsigned short*)&dwTest)[0]), (DWORD)(&((unsigned short*)&dwTest)[1]), (((unsigned short*)&dwTest)[1])); 

((unsigned short*)&dwTest)[0] = (WORD)0xAAAA; 
printf("dwTest = %08X\n", dwTest); 

((unsigned short*)&dwTest)[1] = (WORD)0xBBBB; 
printf("dwTest = %08X\n", dwTest); 

//(Overflow) 
((unsigned short*)&dwTest)[2] = (WORD)0x9999; 

printf("dwTest = %08X\n", dwTest); 

的Visual C++ 2010的輸出(OK):

sizeof(unsigned short) = 2 
dwTest = FFEEDDCC 
Addresses + Values: 0031F728 <- 0000DDCC, 0031F72A <- 0000FFEE 

dwTest = FFEEAAAA 

dwTest = BBBBAAAA 

dwTest = BBBBAAAA 

ARM9 GCC crosstool的輸出(不工作):

sizeof(unsigned short) = 2 
dwTest = FFEEDDCC 
Addresses + Values: 7FAFECD8 <- 0000DDCC, 7FAFECDA <- 0000FFEE 

dwTest = FFEEDDCC 

dwTest = FFEEAAAA 

dwTest = BBBBAAAA 
+0

編譯啓用警告('-Wall')並查看警告。然後在這裏環顧這個「嚴格別名」(解決方案:使用聯盟)。 – ninjalj

回答

2

你所試圖做的是叫類型 - 雙關語。有兩種傳統的方式來做到這一點。

一種方法是通過指針(你所做的)。不幸的是,這與優化器衝突。你看,由於暫停問題,優化器在一般情況下無法知道兩個指針不會互相混疊。這意味着編譯器必須重新加載可能已經通過指針修改的任何值,導致大量潛在的不必要的重新加載。

因此引入了嚴格別名法則。它基本上說,兩個指針只能在相同類型時相互混淆。作爲一個特殊規則,char *可以別名任何其他指針(但不能以其他方式)。 這打破了通過指針的類型雙擊,並讓編譯器生成更高效的代碼。當GCC檢測型雙關,並已打開了警告,它會警告你這樣的:

warning: dereferencing type-punned pointer will break strict-aliasing rules 

另一個辦法型雙關是通過工會:

union { 
    int i; 
    short s[2]; 
} u; 
u.i = 0xDEADBEEF; 
u.s[0] = 0xBABE; 
.... 

這開闢了一個新的整體可的蠕蟲。在最好的情況下,這是依賴於實現的。現在,我沒有權限訪問C89標準,但是在C99中,它最初聲明除了最後一個存儲的聯合成員的值是未指定的。這在TC中被改變以表明不與最後一個存儲成員相對應的字節值是未指定的,並且另外聲明,與最後存儲的成員相對應的字節被重新解釋爲根據新的類型(明顯依賴於實現的東西)。

對於C++,我無法在標準中找到有關聯合黑客的語言。無論如何,C++有reinterpret_cast<>,這就是你應該用C++中的type-punning(使用參考變量reinterpret_cast<>)。

無論如何,你可能不應該使用type-punning(依賴於實現),並且你應該通過位移來手動建立你的值。

+0

感謝您的完整澄清的答案 – Dunge