lvella
lvella

Reputation: 13481

C: position of field of struct inside a union

I have the following type:

union {
  struct {
    uint32_t c0;
    uint32_t k0[4];
    uint32_t c1;
    uint32_t v[2];
    uint32_t i[2];
    uint32_t c2;
    uint32_t k1[4];
    uint32_t c3;
  } named;
  uint32_t array[16];
} state;

because each field inside "named" has a meaning upon initialization, but I will use it mostly as a word array after that. Does C guarantees that state.array[0] is the same as state.named.c0, state.array[1] is state.named.k0[0] and so on?

If not, how likely is it to work? Are there any compiler/platform that break my code if I rely on it?

Upvotes: 4

Views: 1172

Answers (3)

Cornstalks
Cornstalks

Reputation: 38228

From the C Standard:

6.7.2.1/15
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.

6.7.2.1/16
The size of a union is sufficient to contain the largest of its members. The value of at most one of the members can be stored in a union object at any time. A pointer to a union object, suitably converted, points to each of its members (or if a member is a bit- field, then to the unit in which it resides), and vice versa.

Emphasis mine. This basically translates into state.named, state.named.c0, and state.array having the same address. However, and here's the catch, there is no guarantee about where the rest of named's members lie (order in memory is specified, but location is not). There can, technically, be padding in between each of named's members (and even at the end of named as well). So the answer is no, that is not guaranteed. Padding can be added in between your members.

The key is the last sentence of the first quote:

There may be unnamed padding within a structure object

Upvotes: 2

WhozCraig
WhozCraig

Reputation: 66244

To answer your most worrisome question, "..how likely is it to work", don't gamble on likelihood unless it is a sure thing. It isn't in this case.

The standard (§6.7.2.1,p15) dictates the address of the first member of a struct, or of all members of a union, is the same as of the struct or union itself. For you this only means the address of array[16] and named are identical, and both are equivalent to the address of state. However, without implementation-dependent packing, there is no guarantee that the struct will overlay precisely, as the same section of the standard calls out that inter-structure packing is possible.

For example, for whatever reason a compiler working with a packing scheme to always start members on 64bit boundaries could lay out your name as follows:

struct {
    uint32_t c0;
    **padding 4 bytes**
    uint32_t k0[4];
    uint32_t c1;
    **padding 4 bytes**
    uint32_t v[2];
    uint32_t i[2];
    uint32_t c2;
    **padding 4 bytes**
    uint32_t k1[4];
    uint32_t c3;
    **padding 4 bytes**
} name;

In short, all you are guaranteed is that the memory occupied by name as a whole and the memory occupied by the other member of your union, array[16] shall occupy the same memory, starting at the beginning addressable location of each. What that memory looks like under the covers of name's packing is up to the implementation and any packing hints you care to supply.

Some of the relevant portions of the standard:

C99-§6.7.2.1,p6 As discussed in 6.2.5, a structure is a type consisting of a sequence of members, whose storage is allocated in an ordered sequence, and a union is a type consisting of a sequence of members whose storage overlap.

C99-§6.7.2.1,p15 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.

C99-§6.7.2.1,p16 The size of a union is sufficient to contain the largest of its members. The value of at most one of the members can be stored in a union object at any time. A pointer to a union object, suitably converted, points to each of its members (or if a member is a bit- field, then to the unit in which it resides), and vice versa.

C99-§6.7.2.1,p17 There may be unnamed padding at the end of a structure or union.

Upvotes: 3

rajneesh
rajneesh

Reputation: 1749

yes state.array[0] is same as state.named.c0. C guarantees that 'array[16]` and structure named would occupy same area of memory.

This is true as long as data type are matching. for e.g if you are storing 2 sorts and then read a integer the result is machine dependent.

Upvotes: -3

Related Questions