Suppose we have two structs:
typedef struct Struct1
{
short a_short;
int id;
} Struct1;
typedef struct Struct2
{
short a_short;
int id;
short another_short;
} Struct2;
Is it safe to cast from Struct2 *
to Struct1 *
? What does the ANSI spec says about this?
I know that some compilers have the option to reorder structs fields to optimize memory usage, which might render the two structs incompatible. Is there any way to be sure this code will be valid, regardless of the compiler flag?
Thank you!
No, the standard does't allow this; accessing the elements of a Struct2 object through a Struct1 pointer is undefined behavior. Struct1 and Struct2 are not compatible types (as defined in 6.2.7) and may be padded differently, and accessing them via the wrong pointer also violates aliasing rules.
The only way something like this is guaranteed to work is when Struct1 is included in Struct2 as its initial member (6.7.2.1.15 in the standard), as in unwind's answer.
Yes, it is ok to do that!
A sample program is as follows.
struct pointers types always have the same representation in C.
And members in structure types are always in order in C.
The language specification contains the following guarantee
This only applies to type-punning through unions. However, this essentially guarantees that the initial portions of these struct types will have identical memory layout, including padding.
The above does not necessarily allow one to do the same by casting unrelated pointer types. Doing so might constitute a violation of aliasing rules
The only question here is whether accessing
constitutes access to the whole
Struct2
object (in which case it is a violation of 6.5/7 and it is undefined), or merely access to ashort
object (in which case it might be perfectly defined).It general, it might be a good idea to stick to the following rule: type-punning is allowed through unions but not through pointers. Don't do it through pointers, even if you are dealing with two
struct
types with a common initial subsequence of members.It is safe, as far as I know.
But it's far better, if possible, to do:
Then you've even told the compiler that
Struct2
starts with an instance ofStruct1
, and since a pointer to a struct always points at its first member, you're safe to treat aStruct2 *
as aStruct1 *
.It will most probably work. But you are very correct in asking how you can be sure this code will be valid. So: somewhere in your program (at startup maybe) embed a bunch of ASSERT statements which make sure that
offsetof( Struct1.a_short )
is equal tooffsetof( Struct2.a_short )
etc. Besides, some programmer other than you might one day modify one of these structures but not the other, so better safe than sorry.