union, enum, and struct, 以及结构填充和位字段实现。
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
当使用不同类型的成员访问联合成员时,可以从原始类型的表示中预测结果值。没有错误。
Enumerations
枚举类型的一个对象是最小的整数类型包含枚举的范围内实现。
在C和C++中的模式,模式没有-- enum_is_int,如果枚举包含积极的枚举值,该枚举的存储类型是从下面的列表中的第一个符号类型,根据该枚举器枚举的范围。在其他模式,在这种情况下,一个枚举包含任何负面的枚举值,该枚举的存储类型是下列第一,根据该枚举数的范围在枚举:
-
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
.
在混合使用和不使用-enum_is_int选项编译的转换单元以及共享接口或数据结构时,必须注意。在严格C中,枚举数值必须表示为INT。也就是说,他们必须在范围内-2147483648到2147483647,包括在内。对超出范围的枚举数值发出警告:
#66: enumeration value is out of "int" range
Structures
结构可以包含填充,以确保字段正确对齐,并确保结构本身正确地对齐。下图显示了一个常规的、不打包的结构的示例。填充字节1、2和3以确保正确的字段对齐。填充字节11和12以确保正确的结构对齐。函数返回结构的大小,包括填充。
编译器根据结构的定义方式以下列方式之一对结构进行解析:
- 定义为静态或外部结构的结构用零填充。
- 堆栈或堆上的结构,如使用malloc()或AUTO定义的结构,将填充以前存储在这些内存位置中的内容。您不能使用memcmp()来比较以这种方式定义的填充结构。
Bitfields
在非打包结构中,ARM编译器在容器中分配位字段。容器是声明类型的对齐对象。分配Bitfield使指定的第一个字段占用单词中寻址最低的位,具体取决于配置:
小端(Little-endian):最低地址意味着最不重要。大端(Big-endian):最低地址意味着最重要。
在严格的1990 ISO标准C中,唯一允许使用位字段的类型是int、符号int和无符号int。对于非int位字段,编译器将显示一个错误。无符号或无符号限定符声明的普通位字段被视为无符号。例如,intx:10分配一个10位的无符号整数。位字段被分配给具有足够数量未分配位的正确类型的第一个容器,例如:
struct X { int x:10; int y:20; };
第一个声明创建一个整数容器,并将10位分配给x。在第二个声明中,编译器找到具有足够数量未分配位的现有整数容器,并在与x相同的容器中分配y。
位字段完全包含在其容器中。不适合于容器的位字段放置在相同类型的下一个容器中。例如,如果为结构声明了额外的位字段,则z的声明会溢出容器:
struct X { int x:10; int y:20; int z:5; };
编译器为第一个容器分配剩余的两位,并为z分配一个新的整数容器。Bitfield容器可以相互重叠,例如:
struct X { int x:10; char y:2; };
第一个声明创建一个整数容器,并将10位分配给x。这10位占用整数容器的第一个字节和第二个字节的两个位。在第二个声明中,编译器检查char类型的容器。没有合适的容器,因此编译器分配一个新的正确对齐的char容器。
由于CHAR的自然对齐是1,编译器会搜索包含足够数量未分配位的第一个字节,以完全包含位字段。在示例结构中,int容器的第二字节具有分配给x的两个比特,以及未分配的六个比特。编译器在前一个int容器的第二个字节开始分配一个字符容器,跳过分配给x的前两个位,并将两个位分配给y。
如果y被声明为char y:8,编译器会将第二个字节存储起来,并将一个新的char容器分配给第三个字节,因为位字段不能溢出它的容器。下图显示了以下示例结构的位字段分配:
struct X { int x:10; char y:8; };
相同的基本规则适用于具有不同容器类型的位字段声明。例如,向示例结构中添加int位字段会提供:
struct X { int x:10; char y:8; int z:5; }
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:Note
Bitfields in packed structures
8*sizeof(container-type)-1
bits.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
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) */