union, enum, and struct, as well as struct padding and bitfield implementations.

Table 4-9 Compiler storage of data objects by byte alignment

Type Bytes Alignment
char, bool, _Bool 1 Located at any byte address.
short,wchar_t 2 Located at any address that is evenly divisible by 2.
float , int , long , pointer
4 Located at an address that is evenly divisible by 4.
long long , double , long double
8 Located at an address that is evenly divisible by 8.

Unions

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

Enumerations

An object of an enumeration type is the smallest integer type that contains an implementation within the scope of the enumeration.

In C and C++ mode, mode without --enum_is_int, if the enumeration contains positive enumeration values, the storage type of the enumeration is the first symbolic type from the list below, according to the enumerator enumeration range. In other modes, in which case an enumeration contains any negative enumeration value, the storage type of the enumeration is the first of the following, according to the scope of the enumerator in the enumeration:

  • unsigned char if not using --enum_is_int
  • signed char if not using --enum_is_int
  • unsigned short if not using --enum_is_int
  • signed short if not using --enum_is_int
  • signed int
  • unsigned int except C with --strict
  • signed long long except C with --strict
  • unsigned long long except C with --strict .

Care must be taken when mixing translation units and shared interfaces or data structures compiled with and without the -enum_is_int option. In strict C, enumeration values ​​must be represented as INT. That is, they must be in the range -2147483648 to 2147483647, inclusive. Warn about out-of-range enumeration values:

#66: enumeration value is out of "int" range

Structures

Structs can contain padding to ensure that fields are properly aligned, and that the struct itself is properly aligned. The figure below shows an example of a regular, unpacked structure. Bytes 1, 2, and 3 are padded to ensure proper field alignment. Bytes 11 and 12 are padded to ensure proper structure alignment. The function returns the size of the structure, including padding.

The compiler parses the structure in one of the following ways, depending on how the structure is defined:

  • Structures defined as static or external structures are padded with zeros.
  • Structures on the stack or heap, such as those defined with malloc() or AUTO, will be filled with what was previously stored in these memory locations. You cannot use memcmp() to compare padding structures defined this way.

 

 

Bitfields

In unpacked structures, the ARM compiler allocates bit fields in the container. A container is an alignment object of the declared type. Assign a Bitfield so that the first field specified occupies the least addressed bit in the word, depending on the configuration:

Little-endian: The lowest address means the least important. Big-endian: The lowest address means the most important.

 In strict 1990 ISO Standard C, the only types allowed to use bit fields are int, signed int, and unsigned int. The compiler will display an error for non-int bitfields. Ordinary bit fields declared unsigned or unsigned qualifiers are treated as unsigned. For example, intx:10 allocates a 10-bit unsigned integer. Bit fields are assigned to the first container of the correct type with a sufficient number of unassigned bits, for example:

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

 

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

A bit field is completely contained within its container. Bit fields that do not fit into a container are placed in the next container of the same type. For example, if an extra bit field is declared for the struct, the declaration of z overflows the container:

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

The compiler allocates the remaining two bits for the first container and 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 assigns 10 bits to x. These 10 bits occupy the first byte and two bits of the second byte of the integer container. In the second declaration, the compiler checks for a container of type char. There is no suitable container, so the compiler allocates a new properly aligned char container.

Since the natural alignment of CHAR is 1, the compiler searches for the first byte that contains a sufficient number of unallocated bits to fully contain the bit field. In the example structure, the second byte of the int container has two bits allocated for x, and six bits unallocated. The compiler allocates a character container starting at the second byte of the previous int container, skips the first two bits allocated to x, and allocates two bits to y.

If y was declared as char y:8, the compiler would store the second byte and allocate a new char container to the third byte, since a bit field cannot overflow its container. The following figure shows the bit field assignment for the following example structure:

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

 

The same basic rules apply for bit-field declarations with different container types. For example, adding an int bitfield to the example struct provides:

 

struct X
{
    int x:10;
    chary: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, as follows:
Figure 10-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 not empty. A subsequent bitfield declaration starts a new empty container.

Note

As an optimization, the compiler might overwrite padding bits in a container with unspecified values when a bitfield is written. This does not affect normal usage of bitfields.

Bitfields in packed structures

Packed bitfield containers, including all bitfield containers in packed structures, have an alignment of 1. Therefore the maximum bit padding inserted to align a packed bitfield container is 7 bits.
For an unpacked bitfield container, the maximum bit padding is 8*sizeof(container-type)-1 bits.
Tail-padding is always inserted into the structure as necessary to ensure arrays of the structure will have their elements correctly aligned.
A packed bitfield container is only large enough (in bytes) to hold the bitfield that declared it. Non-packed bitfield containers are the size of their type.
The following examples illustrate these interactions.
struct A {          int z:17; }; // sizeof(A) = 4, alignment = 4
struct A { __packed int z:17; }; // sizeof(A) = 3, alignment = 1
__packed struct A { int z:17; }; // sizeof(A) = 3, alignment = 1
struct A { char y:1;          int z:31; }; // sizeof(A) = 4, alignment = 4
struct A { char y:1; __packed int z:31; }; // sizeof(A) = 4, alignment = 1
__packed struct A { char y:1; int z:31; }; // sizeof(A) = 4, alignment = 1
struct A { char y:1;          int z:32; }; // sizeof(A) = 8, alignment = 4
struct A { char y:1; __packed int z:32; }; // sizeof(A) = 5, alignment = 1
__packed struct A { char y:1; int z:32; }; // sizeof(A) = 5, alignment = 1
struct A { int x; char y:1;          int z:31; };  // sizeof(A) = 8, alignment = 4
struct A { int x; char y:1; __packed int z:31; };  // sizeof(A) = 8, alignment = 4
__packed struct A { int x; char y:1; int z:31; };  // sizeof(A) = 8, alignment = 1
struct A { int x; char y:1;          int z:32; };  // sizeof(A) = 12, alignment = 4 [1]
struct A { int x; char y:1; __packed int z:32; };  // sizeof(A) = 12, alignment = 4 [2]
__packed struct A { int x; char y:1; int z:32; };  // sizeof(A) = 9, alignment = 1
Note that [1] and [2] are not identical; the location of z within the structure and the tail-padding differ.
struct example1
{
int a : 8;  /* 4-byte container at offset 0 */
__packed int b : 8;  /* 1-byte container at offset 1 */
__packed int c : 24; /* 3-byte container at offset 2 */
}; /* Total size 8 (3 bytes tail padding) */;
struct example2
{
__packed int a : 8; /* 1-byte container at offset 0 */
__packed int b : 8; /* 1-byte container at offset 1 */
int c : 8; /* 4-byte container at offset 0 */
}; /* Total size 4 (No tail padding) */
struct example3
{
int a : 8;  /* 4-byte container at offset 0 */
__packed int b : 32; /* 4-byte container at offset 1 */
__packed int c : 32; /* 4-byte container at offset 5 */
int d : 16; /* 4-byte container at offset 8 */
int e : 16; /* 4-byte container at offset 12 */
int f : 16; /* In previous container */
}; /* Total size 16 (No tail padding) */
 

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324508345&siteId=291194637