Is this code guaranteed by the C standard?

2019-04-26 16:06发布

问题:

I have read that if you declare two structs like this:

struct Node {
   int a, b, c;
};

struct DerivedNode {
   struct Node base;
   int d, e, f;
};

Then you can use pointers to them like this:

struct DerivedNode myDerivedNode; 
struct Node *regularNode = (struct Node *) &myDerivedNode;

regularNode->a = 3;

In other words, the address offsets for a, b, c are the same within struct Node and struct DerivedNode. So you can get a kind of polymorphism out of it, where you can pass in a forcibly (struct Node *)-cast DerivedNode pointer wherever a Node pointer would normally be taken.

My question is whether this behavior is guaranteed. I know there are some weird memory alignment issues and that the compiler sometimes reorders fields to achieve better packing in memory. Will the base field ever be located anywhere but the beginning of struct DerivedNode?

回答1:

This is guaranteed to work by the standard. Members in structs are layed out sequentially in the order you specify and the first member always appears at offset 0.

Relevant excerpts from the ANSI C standard:

A structure is a type consisting of a sequence of members, whose storage is allocated in an ordered sequence.

This states that the members are laid out sequentially.

There may be unnamed padding within a structure object, but not at its beginning.

The means that the first member is placed at offset 0.

Note: Standard excerpts taken from section 6.7.2.1 of ISO/IEC 9899:TC3 September 2007 draft.



回答2:

As David states this is guaranteed as long as base remains the first element in DerivedNode.

But generally this is bad practice. I can't figure out much circumstances where you can't say

struct Node *regularNode = &myDerivNode.base;

which is much clearer and less error prone in case you modify your structures later on.



回答3:

This won't answer your question, but one who cares to write standard ANSI (ISO) C could compile his code with gcc -pedantic or -pedantic-errors. Those options should raise compiling warnings/errors on non-standard lines of code.

Note that this is not 100% effective, from man gcc:

[-pedantic] finds some non-ISO practices, but not all---only those for which ISO C requires a diagnostic, and some others for which diagnostics have been added.



标签: c struct