Strict aliasing refers to when a pointer is converted to another pointer type, after which the contents are accessed. Strict aliasing means that the involved pointed-at types must be compatible. That does not apply here.
There is however the term pointer aliasing, meaning that two pointers can refer to the same memory. The compiler is not allowed to assume that this is the case here. If it wants to do optimizations like those you describe, it would perhaps have to add machine code that compares the pointers with each other, to determine if they are the same or not. Which in itself would make the function slightly slower.
To help the compiler optimize such code, you can declare the pointers as restrict
, which tells the compiler that the programmer guarantees that the pointers are not pointing at the same memory.
Your function compiled with gcc -O3
results in this machine code:
0x00402D09 mov $0x1,%edx
Which basically means that the whole function was replaced (inlined) with "set a.x to 1".
But if I rewrite your function as
int test_func(A* restrict a, int* restrict x)
{
a->x = 0;
*x = 1;
return a->x;
}
and compile with gcc -O3
, it does return 0. Because I have now told the compiler that a->X
and x
do not point at the same memory, so it can assume that *x = 1;
does not affect the result and skip the line *x = 1;
or sequence it before the line a->x = 0;
.
The optimized machine code of the restrict version actually skips the whole function call, since it knows that the value is already 0 as per your initialization.
This is of course a bug, but the programmer is to blame for it, for careless use of restrict
.
restrict
in C. – Holbertint*
tofloat*
, on a platform withsizeof int == sizeof float
. And I thought that this restriction was due to the fact that each platform may have different alignment requirements, which under certain scenarios might lead to undefined behavior. I don't see any of that in your code. – Universalizevoid*
and then to another type. Here in your case, all type information is present to the compiler, so it must not create problems. – Fulkslong i=1; *(short*)&i = 2;
contains a strict aliasing violation and the compiler is therefore free to give the result 1. Or crash and burn. – Ciafloat f = 5; int i = *(int*)&f;
is not strict aliasing on a platform withsizeof int == sizeof float
(i.e., no UB if ignoring alignment and endianess)? – Universalize(int *)&f
and&f
will even point to the same object, though most real-world compilers and programs assume that it does. – Licenseefloat
andint
, which are not compatible types. And none of the special exceptions (unions, arrays, character types) apply. But this has nothing to do with type sizes or alignment, but with the concept of compatible type in C. – Cia