A language lawyer question. Hmkay.
My personal top3:
- violating the strict aliasing rule
- violating the strict aliasing rule
violating the strict aliasing rule
:-)
Edit Here is a little example that does it wrong twice:
(assume 32 bit ints and little endian)
float funky_float_abs (float *a)
{
unsigned int * temp = (unsigned int*) a;
temp &= 0x7fffffff;
return *(float*)temp;
}
That code tries to get the absolute value of a float by bit-twiddeling with the sign bit directly in the representation of a float.
However, the result of creating a pointer to an object by casting from one type to another is not valid C. The compiler may assume that pointers to different types don't point to the same chunk of memory. This is true for all kind of pointers except void* and char* (sign-ness does not matter).
In the case above I do that twice. Once to get an int-alias for the float *a, and once to convert the value back to float.
There are two valid ways to do the same.
Use a char or void pointer during the cast. These always alias to anything, so they are safe.
float funky_float_abs (float *a)
{
float temp_float = *a;
// valid, because it's a char pointer. These are special.
unsigned char * temp = (unsigned char *) a;
temp[3] &= 0x7f;
return temp_float;
}
Use memcopy. Memcpy takes void pointers, so it will force aliasing as well.
float funky_float_abs (float *a)
{
int temp_int i;
float temp_float result;
memcpy (&i, a, sizeof (int));
i &= 0x7fffffff;
memcpy (&result, &i, sizeof (int));
return result;
}
And while I'm at it: The next code has nothing to do with strict aliasing. It works in practice but it relies on undefined behaviour as well:
float funky_float_abs (float *a)
{
union
{
unsigned int i;
float f;
} cast_helper;
cast_helper.f = *a;
cast_helper.i &= 0x7fffffff;
return cast_helper.f;
}
I'd say is safe to cast via unions even if undefined. If the compiler guys change this behaviour to be standard complient it will simply break to much code.