Jump to content

  • Log In with Google      Sign In   
  • Create Account


#ActualHodgman

Posted 01 January 2013 - 08:04 AM

This is a spin-off from another thread here.

I was advocating the use of a "polymorphic" design, where two structures that have the same initial member were aliased:
namespace Commands
{
	enum Type { Foo };
}
struct Command
{
	Commands::Type id;
};
struct Foo
{
	Commands::Type id;
	int value;
};
//e.g.
Foo foo = { Commands::Foo, 1337 };
Command* cmd = (Command*)&foo;
switch( cmd->id )
{
	case Commands::Foo:
		Foo* fooCmd = (Foo*)cmd;
		printf( "id = %d, value = %d\n", (int)fooCmd->id, fooCmd->value );
		break;
}
At the time, I thought this violated the strict-aliasing rule, but that the code would produce the intended behaviour anyway. The worst thing that I thought would happen, is that the compiler would generate code that redundantly reads "fooCmd->id", even though it already read "cmd->id" just above. 
 
However, the C++03 wording of the rule is:
If a program attempts to access the stored value of an object through an lvalue of other than one of the following types the behavior is undefined:
 
• the dynamic type of the object,
• a cv-qualified version of the dynamic type of the object,
• a type that is the signed or unsigned type corresponding to the dynamic type of the object,
• a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic 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),
• a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,
• a char or unsigned char type.
Does the bold statement mean that I'm not actually breaking the strict aliasing rule here, because the aliased value (i.e. id) is actually the correct type in both structures?

#4Hodgman

Posted 01 January 2013 - 08:03 AM

This is a spin-off from another thread here.

I was advocating the use of a "polymorphic" design, where two structures that have the same initial member were aliased:
namespace Commands
{
	enum Type { Foo };
}
struct Command
{
	Commands::Type id;
};
struct Foo
{
	Commands::Type id;
	int value;
};
//e.g.
Foo foo = { Commands::Foo, 1337 };
Command* cmd = (Command*)&foo;
switch( cmd->id )
{
	case Commands::Foo:
		Foo* fooCmd = (Foo*)cmd;
		printf( "id = %d, value = %d\n", (int)fooCmd->id, fooCmd->value );
		break;
}
At the time, I thought this violated the strict-aliasing rule, but that the code would produce the intended behaviour anyway. The worst thing that I thought would happen, is that the compiler would generate code that redundantly reads "fooCmd->id", even though it already read "cmd->id" just above. 
 
However, the C++03 wording of the rule is:
If a program attempts to access the stored value of an object through an lvalue of other than one of the following types the behavior is undefined:
 
• the dynamic type of the object,
• a cv-qualified version of the dynamic type of the object,
• a type that is the signed or unsigned type corresponding to the dynamic type of the object,
• a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic 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),
• a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,
• a char or unsigned char type.
Does the bold statement mean that I'm not actually breaking the strict aliasing rule here, because the aliased value (i.e. id) is actually the correct type in both structures?

#3Hodgman

Posted 01 January 2013 - 07:54 AM

This is a spin-off from another thread here.

I was advocating the use of a "polymorphic" design, where two structures that have the same initial member were aliased:
namespace Commands
{
	enum Type { Foo };
}
struct Command
{
	Commands::Type id;
};
struct Foo
{
	Commands::Type id;
	int value;
};
//e.g.
Foo foo = { Commands::Foo, 1337 };
Command* cmd = (Command*)&foo;
switch( cmd->id )
{
	case Commands::Foo:
		Foo* fooCmd = (Foo*)cmd;
		printf( "id = %d, value = %d\n", (int)fooCmd->id, fooCmd->value );
		break;
}
At the time, I thought this violated the strict-aliasing rule, but that the code would produce the intended behaviour anyway. The worst thing that I thought would happen, is that the compiler would generate code that redundantly reads "fooCmd->id", even though it already read "cmd->id" just above. 
 
However, the C++03 wording of the rule is:
If a program attempts to access the stored value of an object through an lvalue of other than one of the following types the behavior is undefined:
 
• the dynamic type of the object,
• a cv-qualified version of the dynamic type of the object,
• a type that is the signed or unsigned type corresponding to the dynamic type of the object,
• a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic 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),
• a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,
• a char or unsigned char type.
Does the bold statement mean that I'm not actually breaking the strict aliasing rule here, because the aliased value (i.e. id) is actually the correct type in both structures?

#2Hodgman

Posted 01 January 2013 - 07:53 AM

This is a spin-off from another thread here.

I was advocating the use of a "polymorphic" design, where two structures that have the same initial member were aliased:

struct Command
{
	u8 id;
};
struct Foo
{
	u8 id;
	int value;
};
namespace Commands
{
	enum Type { Foo };
}
//e.g.
Foo foo = { Commands::Foo, 1337 };
Command* cmd = (Command*)&foo;
switch( cmd->id )
{
	case Commands::Foo:
		Foo* fooCmd = (Foo*)cmd;
		printf( "id = %d, value = %d\n", fooCmd->id, fooCmd->value );
		break;
}

At the time, I thought this violated the strict-aliasing rule, but that the code would (most likely) produce the intended behaviour anyway. The worst thing that I thought would happen, is that the compiler would generate code that redundantly reads "fooCmd->id", even though it already read "cmd->id" just above. 

 

However, the C++03 wording of the rule is:

 

If a program attempts to access the stored value of an object through an lvalue of other than one of the following types the behavior is undefined:

 
• the dynamic type of the object,
• a cv-qualified version of the dynamic type of the object,
• a type that is the signed or unsigned type corresponding to the dynamic type of the object,
• a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic 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),
• a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,
• a char or unsigned char type.

 

Does the bold statement mean that I'm not actually breaking the strict aliasing rule here, because the aliased value (i.e. id) is actually the correct type in both structures?


#1Hodgman

Posted 01 January 2013 - 07:51 AM

This is a spin-off from another thread here.

I was advocating the use of a "polymorphic" design, where two structures that have the same initial member were aliased:

struct Command
{
	u8 id;
};
struct Foo
{
	u8 id;
	int value;
};
namespace Commands
{
	enum Type { Foo };
}
//e.g.
Foo foo = { Commands::Foo, 1337 };
Command* cmd = (Command*)&foo;
switch( cmd->id )
{
	case Commands::Foo:
		Foo* fooCmd = (Foo*)cmd;
		printf( "id = %d, value = %d\n", fooCmd->id, fooCmd->value );
		break;
}

At the time, I thought this violated the strict-aliasing rule, but that the code would (most likely) produce the intended behaviour anyway. The worst thing that I thought would happen, is that the compiler would generate code that redundantly reads "fooCmd->id", even though it already read "cmd->id" just above. 

 

However, the C++03 wording of the rule is:

If a program attempts to access the stored value of an object through an lvalue of other than one of the following types the behavior is undefined:

 
• the dynamic type of the object,
• a cv-qualified version of the dynamic type of the object,
• a type that is the signed or unsigned type corresponding to the dynamic type of the object,
• a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic 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),
• a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,
• a char or unsigned char type.

Does the bold statement mean that I'm not actually breaking the strict aliasing rule here, because the aliased value (i.e. id) is actually the correct type in both structures?

PARTNERS