结构体对齐

在上下文及头文件均正常的情况下,以下代码打印的结果是(假设运行在 64 位计算机上):

1
2
3
4
5
6
7
8
struct st_t {
int status;
short *pdata;
char errstr[32];
};
st_t st[16];
char *p = (char *)(st[2].errstr + 32);
printf("%d", (p - (char *)(st)));

A. 32 B. 120 C. 114 D. 144

结构体对齐:

  • 内部对齐:结构体成员之间会留有空隙。
  • 外部对齐:在结构体数组中,结构体之间也可能留有空隙。

对齐规则:

1.第一个成员在与结构体变量偏移量为0的地址

2.其他成员变量要对齐到对齐数的整数倍的地址处(对齐数 = 编译器默认的对齐数(VS中为8) 与 成员变量大小的较小值),即 内部对齐

3.结构体总大小为最大对齐数(每个成员变量都有一个对齐数,取所以成员变量中对齐数最大的)的整数倍外部对齐

4. 如果嵌套结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(包含嵌套结构体的对齐数)的整数倍,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct S3 {
double d; //▣
char c; //▤
int i; //▦
};
//s3内存布局:▣▣▣▣▣▣▣▣▤▢▢▢▦▦▦▦ 最大对齐数为8
↑ ↑ ↑
struct S4 { 0 8 12
int f; //▦
char c; //▤
struct S3 s3;
}; //s4内存布局:▦▦▦▦▤▢▢▢▣▣▣▣▣▣▣▣▤▢▢▢▦▦▦▦
↑ ↑ ↑
0 4 8

为什么要结构体对齐?

  • 平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
  • 性能原因: 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问

如何使结构体内存尽可能小?

根据成员的大小按从大到小的顺序依次声明即可,如double声明在int前,而int声明在char前

修改默认对齐数:

#pragma pack(x)//设置默认对齐数为x
如果不想对齐,直接声明 #pragma pack(1)