This is the mail archive of the
gcc-help@gcc.gnu.org
mailing list for the GCC project.
Re: Strict aliasing, int aliased with struct containing int
- From: Jonathan Wakely <jwakely dot gcc at gmail dot com>
- To: Maxim Mikityanskiy <maxtram95 at gmail dot com>
- Cc: gcc-help <gcc-help at gcc dot gnu dot org>
- Date: Sun, 4 Jan 2015 13:15:22 +0000
- Subject: Re: Strict aliasing, int aliased with struct containing int
- Authentication-results: sourceware.org; auth=none
- References: <CAKErNvqucZuceDu=hjffKScQ_FKv64K+-hA-_8KJdhvTHH7Wgw at mail dot gmail dot com>
On 4 January 2015 at 09:22, Maxim Mikityanskiy <maxtram95@gmail.com> 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;
}