Davide
Davide

Reputation: 101

C struct elements alignment (ansi)

just a simple question... what the standard says about the structure members alignment? for example with this one:

struct
{
    uint8_t a;
    uint8_t b;
    /* other members */
} test;

It is guarateed that b is at offset 1 from the struct start? Thanks

Upvotes: 4

Views: 860

Answers (6)

alk
alk

Reputation: 70981

What is guaranteed by the C-Standard already had been mentioned by other answers.

However, to make sure b is at offset 1 your compiler might offer options to "pack" the structure, will say to explicitly add no padding.

For gcc this can be achieved by the #pragma pack().

#pragma pack(1)
struct
{
  uint8_t a; /* Guaranteed to be at offset 0. */
  uint8_t b; /* Guaranteed to be at offset 1. */
  /* other members are guaranteed to start at offset 2. */
} test_packed;
#pragma pack()

struct
{
  uint8_t a; /* Guaranteed to by at offset 0. */
  uint8_t b; /* NOT guaranteed to be at offset 1. */
  /* other members are NOT guaranteed to start at offset 2. */
} test_unpacked;

A portable (and save) solution would be to simply use an array:

struct
{
  uint8_t ab[2]; /* ab[0] is guaranteed to be at offset 0. */
                 /* ab[1] is guaranteed to be at offset 1. */
  /* other members are NOT guaranteed to start at offset 2. */
} test_packed;

Upvotes: 0

Shafik Yaghmour
Shafik Yaghmour

Reputation: 158629

It should be possible to use offsetof to determine the offset of members.

For C the alignment is implementation defined, we can see that in the draft C99 standard section 6.7.2.1 Structure and union specifiers paragraph 12(In C11 it would be paragraph 14) which says:

Each non-bit-field member of a structure or union object is aligned in an implementation defined manner appropriate to its type.

and paragraph 13 says:

Within a structure object, the non-bit-field members and the units in which bit-fields reside have addresses that increase in the order in which they are declared. A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa. There may be unnamed padding within a structure object, but not at its beginning.

and for C++ we have the following similar quotes from the draft standard section 9.2 Class members paragraph 13 says:

Nonstatic data members of a (non-union) class with the same access control (Clause 11) are allocated so that later members have higher addresses within a class object. The order of allocation of non-static data members with different access control is unspecified (Clause 11). Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other;

and paragraph 19 says:

A pointer to a standard-layout struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa. [ Note: There might therefore be unnamed padding within a standard-layout struct object, but not at its beginning, as necessary to achieve appropriate alignment. —end note ]

Upvotes: 1

Oliver Charlesworth
Oliver Charlesworth

Reputation: 272792

The standard (as of C99) doesn't really say anything.

The only real guarantees are that (void *)&test == (void *)&a, and that a is at a lower address than b. Everything else is up to the implementation.

Upvotes: 7

Kninnug
Kninnug

Reputation: 8063

K&R second edition (ANSI C) in chapter 6.4 (page 138) says:

Don't assume, however, that the size of a structure is the sum of the sizes of its memebers. Because of alignment requirements for different objects, there may be unnamed "holes" in a structure.

So no, ANSI C does not guarantee that b is at offset 1.

It is even likely that the compiler puts b at offset sizeof(int) so that it's aligned on the size of a machine word, which is easier to deal with.

Some compilers support pack-pragmas so that you can force that there are no such "holes" in the struct, but that is not portable.

Upvotes: 0

nesderl
nesderl

Reputation: 325

the case you're using is not really an edge case, both uint_8 are small enough to fit in the same word in memory and it would be no use to put each uint_8 in a uint_16.

A more critical case would be something like :

{
    uint8_t a;
    uint8_t b;

    uint_32 c; // where is C, at &a+2 or &a+4 ?
    /* other members */
} test;

and anyway this will always depend on the target architecture and your compiler...

Upvotes: 0

simonc
simonc

Reputation: 42215

C11 6.7.2.1 Structure and union specifiers p14 says

Each non-bit-field member of a structure or union object is aligned in an implementation- defined manner appropriate to its type.

meaning that you can't make any portable assumptions about the difference between the addresses of a and b.

Upvotes: 1

Related Questions