首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Objects and alignment

C程序创建,销毁,访问和操作对象。

C中的对象是执行环境中的数据存储区域,其内容可以表示(当解释为具有特定类型时,值是对象内容的含义)。

每个对象都有。

  • 大小(可以用sizeof来确定)
  • 对齐要求(可以通过alignof来确定)(因为C11)
  • 存储时间(自动,静态,分配,线程本地)
  • 寿命(等于存储时间或临时)
  • 有效的类型(见下文)
  • 价值(可能是不确定的)
  • 可选地,表示该对象的标识符

对象由声明,分配函数,字符串文字,复合文字以及通过返回具有数组成员的结构或联合的非左值表达式创建。

对象表示

除了位字段,对象由一个或多个字节的连续序列组成,每个字节由CHAR_BIT位组成,可以复制memcpy到一个类型的对象中unsigned char[n],其中n对象的大小就是这样。结果数组的内容被称为对象表示

如果两个对象具有相同的对象表示形式,则它们会相等(除非它们是浮点型NaN)。相反的情况并非如此:比较相等的两个对象可能具有不同的对象表示,因为对象表示的每一位都不需要参与该值。这些位可用于填充以满足对齐要求,用于奇偶校验,指示陷印表示等。

如果对象表示不表示对象类型的任何值,则称为陷阱表示。除了通过字符类型的左值表达式读取陷阱表达以外的任何其他方式都是未定义的行为。即使任何特定的成员是一个结构或联合的价值,也不是陷阱表示。

对于类型为char,signed char和unsigned char的对象,要求对象表示的每一位参与值表示,并且每个可能的位模式表示不同的值(不允许填充,陷阱位或多个表示形式)。

有效类型

每个对象都有一个有效的类型,它确定哪些左值访问是有效的,哪些违反了严格的别名规则。

如果对象是由声明创建的,则该对象的声明类型是对象的有效类型

如果对象是由分配函数(包括realloc)创建的,则它没有声明类型。这样的对象获得如下有效类型:

  • 第一次通过一个左值写入该对象,该左值的类型不是字符类型,此时该左值的类型变为该对象的该写入的有效类型以及所有后续读取。
  • memcpy或者memmove将另一个对象复制到该对象中,此时源对象的有效类型(如果有的话)成为该对象的有效类型以及所有后续读取。
  • 对没有声明类型的对象进行任何其他访问,有效类型是用于访问的左值的类型。

严格的别名

给定一个有效类型为 T1 的对象,使用不同类型T2的左值表达式(通常是解引用指针)是未定义的行为,除非:

  • T2和T1是兼容的类型。
  • T2是与T1兼容的类型的cvr限定版本。
  • T2是与T1兼容的类型的有符号或无符号版本。
  • T2是一种聚合类型或联合类型类型,其成员之一包括上述类型之一(包括递归地,子聚合的成员或包含的联合)。
  • T2是一种字符类型(char,signed char或unsigned char)。
代码语言:javascript
复制
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)

为了满足结构中所有成员的对齐要求,可以在其一些成员之后插入填充。

代码语言:javascript
复制
#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));
}

可能的输出:

代码语言:javascript
复制
sizeof(struct S) = 2
alignof(struct S) = 1
sizeof(struct X) = 8
alignof(struct X) = 4

每种对象类型都对该类型的每个对象强加对齐要求。任何类型最严格的(最大的)基本对齐方式都是对齐max_align_t。最弱(最小)的对准是种类的排列charsigned char以及unsigned char,和等于1。

如果使用alignas将对象的对齐更严格(大于)max_align_t,则它具有扩展的对齐要求。其成员具有扩展对齐的结构或联合类型是超对齐类型。如果支持过度对齐类型,它是实现定义的,并且它们的支持在每种存储持续时间中可能不同。

(自C11以来)

扫码关注腾讯云开发者

领取腾讯云代金券

http://www.vxiaotou.com