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


I'm really confused.

uint8_t hash[20];
uint32_t u;

// Setting hash to some value here...

u = *(uint32_t*) hash;

This *(uint32_t*) hash causes a warning:

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

I think it's something wrong in typecasting, but I'm not sure, because I don't clearly know on how *(type*) var way of typecasting actually works. It seem to point on an object with an asterisk inside too. I am confused, that's the thing which forces me to ask a question about that.
Especially I'd like to know how type* differs from *(type*). This may be a lot of help to get rid of this warning.
Thanks in advance.

Best Solution

You are not allowed to interpret an object trough an incompatible pointer as you do:

*(uint32_t*) hash;

Doing that will cause problems with alignment, endianness and violating strict aliasing which will cause undefined behaviour.

What happens is, you interpret the first four bytes of the array hash as an unsigned 32 bit integer.

 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

If your byte array is encoding little endian 32 bit unsigned integer, this is the portable, byte-order independent way of extracting:

#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
Related Question