Objects and alignment
对象和对齐
C程序创建,销毁,访问和操作对象。
C中的对象是执行环境中的数据存储区域,其内容可以表示值
(当解释为具有特定类型时,值
是对象内容的含义)。
每个对象都有。
- 大小(可以用sizeof来确定)
对象由声明,分配函数,字符串文字,复合文字以及通过返回具有数组成员的结构或联合的非左值表达式创建。
对象表示
除了位字段,对象由一个或多个字节的连续序列组成,每个字节由CHAR_BIT
位组成,可以复制memcpy
到一个类型的对象中unsigned char[n]
,其中n
对象的大小就是这样。结果数组的内容被称为对象表示
。
如果两个对象具有相同的对象表示形式,则它们会相等(除非它们是浮点型NaN)。相反的情况并非如此:比较相等的两个对象可能具有不同的对象表示,因为对象表示的每一位都不需要参与该值。这些位可用于填充以满足对齐要求,用于奇偶校验,指示陷印表示等。
如果对象表示不表示对象类型的任何值,则称为陷阱表示
。除了通过字符类型的左值表达式读取陷阱表达以外的任何其他方式都是未定义的行为。即使任何特定的成员是一个结构或联合的价值,也不是陷阱表示
。
对于类型为char,signed char和unsigned char的对象,要求对象表示的每一位参与值表示,并且每个可能的位模式表示不同的值(不允许填充,陷阱位或多个表示形式)。
有效类型
每个对象都有一个有效的类型
,它确定哪些左值访问是有效的,哪些违反了严格的别名规则。
如果对象是由声明创建的,则该对象的声明类型是对象的有效类型
。
如果对象是由分配函数(包括realloc
)创建的,则它没有声明类型。这样的对象获得如下有效类型:
- 第一次通过一个左值写入该对象,该左值的类型不是字符类型,此时该左值的类型变为该对象的该写入的
有效类型
以及所有后续读取。
严格的别名
给定一个有效类型为
T1 的对象,使用不同类型T2的左值表达式(通常是解引用指针)是未定义的行为,除非:
- T2和T1是兼容的类型。
int i = 7;
char* pc = (char*)(&i
if(pc[0] == '\x7') // aliasing through char is ok
puts("This system is little-endian"
else
puts("This system is big-endian"
float* pf = (float*)(&i
float d = *pf; // UB: float lvalue *p cannot be used to access int
请注意,也可以通过联合的非活动成员执行类型双关。
对准
每个完整的对象类型都有一个称为对齐需求
的属性,它是一个类型的整数值,size_t
表示可以分配此类对象的连续地址之间的字节数。有效的对齐值是两个非负整数幂。
The alignment requirement of a type can be queried with alignof. | (since C11) |
---|
为了满足结构中所有成员的对齐要求,可以在其一些成员之后插入填充。
#include <stdio.h>
#include <stdalign.h>
// objects of struct S can be allocated at any address
// because both S.a and S.b can be allocated at any address
struct S {
char a; // size: 1, alignment: 1
char b; // size: 1, alignment: 1
}; // size: 2, alignment: 1
// objects of struct X must be allocated at 4-byte boundaries
// because X.n must be allocated at 4-byte boundaries
// because int's alignment requirement is (usually) 4
struct X {
int n; // size: 4, alignment: 4
char c; // size: 1, alignment: 1
// three bytes padding
}; // size: 8, alignment: 4
int main(void)
{
printf("sizeof(struct S) = %zu\n", sizeof(struct S)
printf("alignof(struct S) = %zu\n", alignof(struct S)
printf("sizeof(struct X) = %zu\n", sizeof(struct X)
printf("alignof(struct X) = %zu\n", alignof(struct X)
}
可能的输出:
sizeof(struct S) = 2
alignof(struct S) = 1
sizeof(struct X) = 8
alignof(struct X) = 4
每种对象类型都对该类型的每个对象强加对齐要求。任何类型最严格的(最大的)基本对齐方式都是对齐max_align_t
。最弱(最小)的对准是种类的排列char
,signed char
以及unsigned char
,和等于1。
如果使用alignas将对象的对齐更严格(大于)max_align_t,则它具有扩展的对齐要求。其成员具有扩展对齐的结构或联合类型是超对齐类型。如果支持过度对齐类型,它是实现定义的,并且它们的支持在每种存储持续时间中可能不同。 | (自C11以来) |
---|