On 4 January 2015 at 09:22, Maxim Mikityanskiy <maxtram95@xxxxxxxxx> wrote: > Hello! > > I'm trying to understand strict aliasing rules, and I have some > questions. Of course, I tried googling a lot first, but my > understanding contradicts with GCC behavior, so I got stucked. > > It's worth noting that I'm using GCC 4.9.2 on x86_64 and write code in > C. I compile it with -O3, so -fstrict-aliasing is implied. > > According to C99 (6.5/7): > > > An object shall have its stored value accessed only by an lvalue > expression that has one of the following types: > - a type compatible with the effective type of the object, > <...> > - an aggregate or union type that includes one of the aforementioned > types among its members (including, recursively, a member of a > subaggregate or contained union), or > <...> > > > As far as I understand this text, it's allowed to access int object > using pointer to struct that contains int field. I don't think your example is valid according to that text. In the expression param->value you are not accessing the object through the aggregate type, you are accessing it through an lvalue of type int, so the second bullet doesn't apply. To modify the stored value through the aggregate type would be done like this: *param = (struct aggregate){ 2 }; However, that has undefined behaviour because it writes sizeof(struct aggregate) bytes to *param which points to an object of only sizeof(int) bytes. The compiler assumes that you would not write a program with undefined behaviour, therefore it can assume that ¶m does not alias global. If you make sizeof(struct aggregate) == sizeof(int) there is no undefined behaviour, and the compiler assumes that the pointer might alias the global. This gives the result you expect: #include <stdio.h> int global; struct aggregate { int value; }; int modify(struct aggregate *param) { global = 1; *param = (struct aggregate){ 2 }; return global; } int main() { printf("%d\n", modify((struct aggregate *)&global)); return 0; }