2014-11-03 81 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

相关问题