2014-11-03 31 views
3

我真的很困惑。解引用類型指針會打破嚴格別名規則[-Wstrict-aliasing]

uint8_t hash[20]; 
uint32_t u; 

// Setting hash to some value here... 

u = *(uint32_t*) hash; 

*(uint32_t*) hash將導致警告:

Dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]

我認爲這是錯誤的類型轉換,但我不確定,因爲我不清楚如何*(type*) var類型轉換的方式實際工作。它似乎指向內部帶有星號的物體。我很困惑,這就是迫使我問一個關於這個問題的事情。 特別是我想知道type**(type*)的區別。這可能有很多幫助擺脫這個警告。 在此先感謝。

回答

1

你不允許解釋對象低谷,你做一個不兼容的指針:

*(uint32_t*) hash; 

否則會引起對齊,字節順序和違反嚴格別名,這將導致不可預知的問題。

會發生什麼情況是,您將數組散列的前四個字節解釋爲無符號的32位整數。

uint32_t* p = (uint32_t*)hash ; //cast must be there, pointer p is not valid 
uint32_t u = *p ; //dereference the pointer, this is undefined behaviour 

如果你的字節數組編碼小尾數32位無符號整數,這是提取的便攜,字節順序無關的方式:

#include <stdint.h> 
#include <limits.h> 

uint8_t h[] = { 3 , 2 , 1 , 0 } ; //1*3 + 256*2 + 65536*1 + 16777216 * 0 
uint32_t a = 0 ; 

for(size_t i = 0 ; i < sizeof(a) ; i++) 
{ 
    a = a | ( h[i] << (CHAR_BIT*i)) ; 
} 

printf("%u" , a) ; //66051 
+1

謝謝了許多的幫助!我不知道這是非法操作。 – Duosora 2014-11-03 12:09:34

+1

嚴格的別名規則不是關於endiannes(儘管這可能是一個問題),但由於規範不允許別名類型,編譯器會做出可能證明無效的假設,導致隱含的錯誤。您可以通過在編譯時使用-fno-strict-aliasing標誌來避免這種情況。 – doron 2014-11-03 12:54:58

+0

@doron你不應該那樣做。列出的其他問題仍然會導致未定義的行爲。請不要低估正確的答案。 – 2501 2014-11-03 12:56:02

相關問題