Sources ?
Ce genre de choses :
int foo (float *f, int *i) {
int j = *i;
*f = 0;
return j;
}
GCC a tendance à considérer que
(void*)i != (void*)f et que donc cela revient à faire :
int foo (float *f, int *i) {
*f = 0;
return *i;
}
et à optimiser agressivement.
Mais rien n'interdit d'utiliser la même adresse successivement pour deux types incompatibles, ce qui est interdit en C est :
int float_to_int(float f) {
return *(int*)&f;
}
parce que float et int ne sont pas compatibles au niveau de la représentation, et qu'on ne peut pas lire un objet d'un type avec un valeur-g d'un autre type.
La doc :
-fstrict-aliasing
Allow the compiler to assume the strictest aliasing rules applicable to the language being compiled. For C (and C++), this activates optimizations based on the type of expressions. In particular, an object of one type is assumed never to reside at the same address as an object of a different type, unless the types are almost the same. For example, an unsigned int can alias an int, but not a void* or a double. A character type may alias any other type.
Pay special attention to code like this:
union a_union {
int i;
double d;
};
int f() {
union a_union t;
t.d = 3.0;
return t.i;
}
The practice of reading from a different union member than the one most recently written to (called “type-punning”) is common. Even with -fstrict-aliasing, type-punning is allowed, provided the memory is accessed through the union type. So, the code above works as expected. See Structures unions enumerations and bit-fields implementation. However, this code might not:
int f() {
union a_union t;
int* ip;
t.d = 3.0;
ip = &t.i;
return *ip;
}
Similarly, access by taking the address, casting the resulting pointer and dereferencing the result has undefined behavior, even if the cast uses a union type, e.g.:
int f() {
double d = 3.0;
return ((union a_union *) &d)->i;
}
The -fstrict-aliasing option is enabled at levels -O2, -O3, -Os.
http://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/Optimize-Options.html