Does this code violate strict aliasing rule? Why or why not?
#include <stdlib.h>
#define STRUCT struct {int x; char y;}
typedef STRUCT my_struct_t;
void get(my_struct_t *data, int *x, char *y)
{
*x = data->x;
*y = data->y;
}
int main(void)
{
STRUCT *data = malloc(sizeof(*data));
data->x=100;
data->y=55;
int x;
char y;
get((my_struct_t*)data, &x, &y);
return 0;
}
Since structs are not compatible because they don't share a tag my guess would be that this code violates the strict aliasing rule.
The structure pointer data
is pointing to a different type from my_struct_t
because you have struct { … } *data = …;
in main()
(after macro expansion), and each time you have struct { … }
, you are defining a new type distinct from any other type, even if those structure types have the same members.
C11 §6.7.2.1 Structure and union specifiers ¶8 says:
The presence of a struct-declaration-list in a struct-or-union-specifier declares a new type, within a translation unit.
The italicized terms are part of the syntax of the structure (and union) grammar.
Consequently, you are casting between types with the call
get((my_struct_t*)data, &x, &y);
In theory, that means undefined behaviour. In practice, it will work with almost any compiler.
I tried using both GCC 11.2.0 and Apple Clang 14.0.0 with extensive options on your code, which I changed to specify static
before the definition of get()
to avoid errors for "no previous prototype for 'get'":
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes \
-fno-common -pedantic -pedantic-errors -fstrict-aliasing -Wstrict-aliasing=2 \
-c sa43.c
$ clang -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes \
-fno-common -pedantic -Weverything -Wno-nullability-extension \
-Wno-nullability-completeness -pedantic-errors -fstrict-aliasing \
-Wstrict-aliasing=2 -c sa43.c
$
The -Weverything
flag for Clang triggers complaints about padding (-Wpadded
, could be suppressed by -Wno-padded
). That then exposes a complaint about using /usr/local/include
because of -Wpoison-system-directories
. The Clang -Weverything
option is not all that helpful because it activates too many warnings, but adding -Wno-poison-system-directories
(as well as -Wno-padded
) allows the code to compile cleanly.
The -Wno-nullability-extension
and -Wno-nullability-completeness
are an extremely irritating necessity because otherwise the system headers fail horribly on my MacBook Pro running macOS Monterey 12.6.3.
So, de facto, your code is OK — but de jure, you are casting between different types.