3.3.4. Structures, unions, enumerations, and bitfields

This section describes the implementation of the structured data types union, enum, and struct. It also discusses structure padding and bitfield implementation.

Unions

When a member of a union is accessed using a member of a different type, the resulting value can be predicted from the representation of the original type. No error is given.

Enumerations

An object of type enum is implemented in the smallest integral type that contains the range of the enum. The type of an enum is one of the following, according to the range of the enum:

  • unsigned char

  • signed char

  • unsigned short

  • signed short

  • unsigned int (C++ always, C except when -strict)

  • signed int.

Implementing enum in this way can reduce data size. The command-line option -fy sets the underlying type of enum to signed int. See About the C and C++ compilers for more information on the -fy option.

Unless you use the -strict option, enum declarations can have a comma at the end as in:

enum { x = 1, };

Structures

The following points apply to:

  • all C structures

  • all C++ structures and classes not using virtual functions or base classes.

Structure alignment

The alignment of a nonpacked structure is the maximum alignment required by any of its fields.

Field alignment

Structures are arranged with the first-named component at the lowest address. Fields are aligned as follows:

  • A field with a char type is aligned to the next available byte.

  • A field with a short type is aligned to the next even-addressed byte.

  • Bitfield alignment depends on how the bitfield is declared. See Bitfields in packed structures for more information.

  • All other types are aligned on word boundaries.

Structures can contain padding to ensure that fields are correctly aligned and that the structure itself is correctly aligned. Figure tgcrf31 shows an example of a conventional, nonpacked structure. Bytes 1, 2, and 3 are padded to ensure correct field alignment. Bytes 11 and 12 are padded to ensure correct structure alignment. The sizeof() function returns the size of the structure including padding.

The compiler pads structures in one of two ways, according to how the structure is defined:

  • Structures that are defined as static or extern are padded with zeros.

  • Structures on the stack or heap, such as those defined with malloc() or auto, are padded with whatever was previously stored in those memory locations. You cannot use memcmp() to compare padded structures defined in this way (Figure tgcrf31). Use the -W+s option to generate a warning when the compiler inserts padding in a struct.

    Figure tgcrf31. Conventional structure example

  • Structures with empty initializers are allowed in C++ and only warned about in C (if C and -strict an error is generated):

    struct { int x; } X = { };
    

Packed structures

A packed structure is one where the alignment of the structure, and of the fields within it, is always 1. Floating-point types cannot be fields of packed structures.

Packed structures are defined with the __packed qualifier. (See ARM-specific keywords.) There is no command-line option to change the default packing of structures.

Bitfields

In nonpacked structures, the ARM compilers allocate bitfields in containers. A container is a correctly aligned object of a declared type. Bitfields are allocated so that the first field specified occupies the lowest-addressed bits of the word, depending on configuration:

Little-endian

Lowest addressed means least significant.

Big-endian

Lowest addressed means most significant.

A bitfield container can be any of the integral types.

Note

The compiler warns about non int bitfields. You can disable this warning with the -Wb compiler option.

A plain bitfield, declared without either signed or unsigned qualifiers, is treated as unsigned. For example, int x:10 allocates an unsigned integer of 10 bits.

A bitfield is allocated to the first container of the correct type that has a sufficient number of unallocated bits, for example:

struct X {
    int x:10;
    int y:20;
};

The first declaration creates an integer container and allocates 10 bits to x. At the second declaration, the compiler finds the existing integer container with a sufficient number of unallocated bits, and allocates y in the same container as x.

A bitfield is wholly contained within its container. A bitfield that does not fit in a container is placed in the next container of the same type. For example, the declaration of z overflows the container if an additional bitfield is declared for the structure above:

struct X {
    int x:10;
    int y:20;
    int z:5;
};

The compiler pads the remaining two bits for the first container and assigns a new integer container for z.

Bitfield containers can overlap each other, for example:

struct X {
    int x:10;
    char y:2;
};

The first declaration creates an integer container and allocates 10 bits to x. These 10 bits occupy the first byte and two bits of the second byte of the integer container. At the second declaration, the compiler checks for a container of type char. There is no suitable container, so the compiler allocates a new correctly aligned char container.

Because the natural alignment of char is 1, the compiler searches for the first byte that contains a sufficient number of unallocated bits to completely contain the bitfield. In the above example, the second byte of the int container has two bits allocated to x, and six bits unallocated. The compiler allocates a char container starting at the second byte of the previous int container, skips the first two bits that are allocated to x, and allocates two bits to y.

If y is declared char y:8, the compiler pads the second byte and allocates a new char container to the third byte, because the bitfield cannot overflow its container (Figure 3.2).

struct X {
    int x:10;
    char y:8;
};

Figure 3.2. Bitfield allocation 1

Note

The same basic rules apply to bitfield declarations with different container types. For example, adding an int bitfield to the example above gives:

struct X {
    int x:10;
    char y:8;
    int z:5;
}

The compiler allocates an int container starting at the same location as the int x:10 container and allocates a byte-aligned char and 5-bit bitfield (Figure 3.3).

Figure 3.3. Bitfield allocation 2

You can explicitly pad a bitfield container by declaring an unnamed bitfield of size zero. A bitfield of zero size fills the container up to the end if the container is non-empty. A subsequent bitfield declaration starts a new empty container.

Bitfields in packed structures

Bitfield containers in packed structures have an alignment of 1. Therefore, the maximum bit padding for a bitfield in a packed structure is 7 bits. For an unpacked structure, the maximum padding is 8*sizeof(container-type)–1 bits.

Copyright © 1999-2001 ARM Limited. All rights reserved.ARM DUI 0067D
Non-Confidential