In the C language, we cannot access an object using an lvalue expression that has an incompatible type with the effective type of that object as this yields to undefined behaviour. And based on this fact, the strict aliasing rule states that two pointers cannot alias each other (refer to the same object in memory) if they have incompatible types. But in p6.2.4 of C11 standard, it is allowed to access an unsigned effective type with a signed version lvalue and vice-versa.
Because of the last paragraph two pointers int *a
and unsigned *b
may alias each other and the change of the value of the object pointed by one of them might lead to the change of the value of the object pointed by the other (Because it is the same object).
Let's demonstrate this on the compiler level:
int f (int *a, unsigned *b)
{
*a = 1;
*b = 2;
return *a;
}
The generated assembly of the above function looks like this on GCC 6.3.0 with -O2:
0000000000000000 <f>:
0: movl $0x1,(%rdi)
6: movl $0x2,(%rsi)
c: mov (%rdi),%eax
e: retq
Which is quite expected because GCC doesn't optimize the return value and still reads the value *a
again after the write to *b
(Because the change of *b
might lead to the change of *a
).
But with this other function :
int ga;
unsigned gb;
int *g (int **a, unsigned **b)
{
*a = &ga;
*b = &gb;
return *a;
}
The generated assembly is quite surprising (GCC -O2):
0000000000000010 <g>:
10: lea 0x0(%rip),%rax # 17 <g+0x7>
17: lea 0x0(%rip),%rdx # 1e <g+0xe>
1e: mov %rax,(%rdi)
21: mov %rdx,(%rsi)
24: retq
The return value is optimized and it is not read again after the write to *b
. I know that int *a
and unsigned *b
are not compatible types but what about the rule in paragraph P6.2.4 (It is allowed to access an unsigned effective type with a signed version lvalue and vice-versa)? Why doesn't it apply in this situation? And why does the compiler make that kind of optimization in this case?
There is somthing I don't understand about this whole story of compatible types and strict aliasing. Can someone enlighten us? (And please explain why do two pointers have incompatible types but can alias each other, think of int *a
and unsigned *b
).