Jump to content

  • Log In with Google      Sign In   
  • Create Account

FREE SOFTWARE GIVEAWAY

We have 4 x Pro Licences (valued at $59 each) for 2d modular animation software Spriter to give away in this Thursday's GDNet Direct email newsletter.


Read more in this forum topic or make sure you're signed up (from the right-hand sidebar on the homepage) and read Thursday's newsletter to get in the running!


#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