Jump to content

  • Log In with Google      Sign In   
  • Create Account


#ActualDracoLacertae

Posted 06 April 2013 - 02:39 PM

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? 


#2DracoLacertae

Posted 06 April 2013 - 02:34 PM

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 the warnings>


#1DracoLacertae

Posted 06 April 2013 - 02:28 PM

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.

 


PARTNERS