Home > Software engineering >  C standard for member offsets of standard layout struct
C standard for member offsets of standard layout struct

Time:02-06

Does the C 11 standard guarantee that all compilers will choose the same memory offsets for all members in a given standard layout struct, assuming all members have guaranteed sizes (e.g. int32_t instead of int)?

That is, for a given member in a standard layout struct, does C 11 guarantee that offsetof will give the same value across all compilers?

If so, is there any specification of what that value would be, e.g. as a function of size, alignment, and order of the struct members?

CodePudding user response:

There is no guarantee that offsetof will yield the same values across compilers.

There are guarantees about minimum sizes of types (e.g., char >= 8 bits, short, int >= 16 bits, long >= 32 bits, long long >= 64 bits), and the relationship between sizes1 (sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)).

For most types, it's guaranteed that the alignment requirement is no greater than the size of the type.

For any struct/class, the first element must be at the beginning of the class/struct, and in the absence of changes to the visibility, order is guaranteed to be in the order of definition. For example:

struct { // same if you use `class`
    int a;
    int b;
};

Since these are both public, a and b must be in that order. But:

struct {
    int a;
    int b;
private:
    int c;
};

The first element (a) is required to be at the beginning of the struct, but because of the change from public to private, the compiler is (theoretically) allowed to arrange c before b.

This rule has changed over time though. In C 98, even a vacuous visibility specifier allowed rearrangement of members.

struct A {
    int a;
    int b;
public:
    int c;
};

The public allows rearranging b and c even though they're both public. Since then it's been tightened up, and in C 23 the whole idea of rearranging elements based on visibility is gone (and long past time, in my opinion--I don't think anybody ever used it, so it's always been a rule you sort of needed to know, but did nobody any real good).


  1. If you want to get really technical, the requirement isn't really on the size, but on the range, so in theory the relationship between sizes isn't quite guaranteed, but for for most practical purposes, it is.

CodePudding user response:

No, there are no such guarantees. The C standard explicitly provides for type-specific padding and alignment requirements, for one thing, and that automatically dissolves this kind of guarantee.

It might be reasonable to anticipate uniform padding and alignment requirements for a specific hardware platform, that all compilers on that platform will implement, but that again is not guaranteed.

CodePudding user response:

Absolutely not. Memory layout is completely up to the C implementation. The only exception, only for standard-layout classes, is that the first non-static data member or base class subobject(s) have zero offset. There are also some other constraints, e.g. due to sizes and alignment of subobjects and constraints on ordering of addresses of subobjects, but nothing that determines concrete offsets of subobjects.

However, typically compilers follow some ABI specification on any given architecture/platform, so that compilers for the same architecture/platform will likely use the same ABI and same memory layout (e.g. the SysV x86-64 ABI together with the Itanium C ABI on Linux x86-64 at least for both GCC and Clang).

  • Related