I'm cleaning up some of my code by compiling with gcc -Wall and -Wstrict-aliasing=1 to look for unclean things I've done.
This is a fairly common pattern in my C code:
typedef struct generic_list_s
{
int type;
struct generic_list_s* next;
} generic_list_t;
typedef struct
{
generic_list_t gen;
char* str;
} string_t;
typedef struct
{
generic_list_t gen;
int x;
} int_t;
The general idea is I have some generic structure that I reuse as the 1st element of larger, more specific structures. The C standard allows you to cast a pointer back and forth between a struct, and it's 1st member. A pointer to an int_t or a string_t in the above examples is also a pointer to a generic_list_t.
GCC however likes to complain. If I compile a snippet like this:
string_t* node0;
int_t* node1;
string_t* node2;
node0 = mk_string("Hello");
node1 = mk_int(123);
node2 = mk_string("World");
/* Below seems correct
node1 is a pointer to an int_t
int_t starts with generic_list_t, so
a pointer to int_t is also a pointer to int_t
(6.7.2.1.13 says )
*/
node0->gen.next = (generic_list_t*) node1;
node1->gen.next = (generic_list_t*) node2;
with -Wstring-aliasing =1, I get this warning:
warning: dereferencing type-punned pointer might break strict-aliasing rules
This makes sense, in that node1 is a pointer to an int_t, and node0->gen.next is technically a pointer to a generic_list_t. I have two different types of pointers pointing to the same thing. I can make it go away by doing this:
node0->gen.next = &(node1->gen);
node1->gen.next = &(node2->gen);
Which is more correct, although a pointer to the first element of a struct or a pointer to the struct are supposed to be compatible with each other.
The real problem comes with functions like:
void print_thing(generic_list_t* n)
{
if (n->type == TYPE_STRING)
{
string_t* s = (string_t*) n;/* warning: dereferencing type-punned pointer might break strict-aliasing rules*/
printf("%s\n", s->str);
}
if (n->type == TYPE_INT)
{
int_t* i = (int_t*) n; /* warning: dereferencing type-punned pointer might break strict-aliasing rules*/
printf("%d\n", i->x);
}
}
Hoe do I clean up these warnings?