union, enum, and struct, 以及结构填充和位字段实现。

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

TypeBytesAlignment
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;
}
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) */
 

 

posted @ 2018-04-16 22:05  QIYUEXIN  阅读(749)  评论(0编辑  收藏  举报