C 语言中结构体内存对齐是指结构体成员在内存中的存储方式并非是紧凑排列的,而是按照一定的规则进行对齐。
#include <stdio.h>
struct s1
{
char c1; // 1 字节
int i; // 4 字节
char c2; // 1 字节
};
struct s2
{
char c1; // 1 字节
char c2; // 1 字节
int i; // 4 字节
};
int main()
{
printf("struct s1 的大小: %d\n", sizeof(struct s1));
printf("struct s2 的大小: %d\n", sizeof(struct s2));
return 0;
}
上述代码,打印的时候,你会不会觉得都是6呢,其实在vs编译器下不是这样的。接下来就说一下为什么。
结构体内存对齐规则如下:
1. 结构体的第一个成员对齐到和结构体变量起始位置偏移量为 0 的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。对齐数等于编译器默认的一个对齐数与该成员变量大小的较小值。例如,在 Visual Studio 中默认的值为 8;在 Linux 中 gcc 没有默认对齐数,对齐数就是成员自身的大小。
3. 结构体总大小为最大对齐数(结构体中每个成员变量都有一个对齐数,所有对齐数中最大的)的整数倍。
4. 如果嵌套了结构体,嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍。
在上述代码中,定义了两个结构体 s1 和 s2 ,它们的成员相同,只是顺序不同。
对于结构体 s1 ,按照内存对齐规则:
- c1 是第一个成员,从偏移量为 0 的地址开始存储。
- i 是 4 字节大小,它的对齐数是 4(取编译器默认对齐数 8 和自身大小 4 的较小值),所以要从 4 的整数倍地址开始存储,即从偏移量为 4 的地址开始存放 i 。所以这里c1存储完,就浪费三个字节,才存储的i。
- c2 是 1 字节,可放在 i 后面的任意地址,但为了满足结构体总大小是最大对齐数(4)的整数倍这一规则,结构体 s1 的总大小需要是 4 的整数倍,4+4+1=9,找到最小的4的倍数,所以 c2 后面会填充 3个字节的空白,使得结构体 s1 的大小为 12 字节。
对于结构体 s2 :
- c1 从偏移量为 0 的地址开始存储。
- c2 紧接着 c1 存放。
- i 同样要从 4 的整数倍地址开始存储, c2 后面需要填充 2个字节的空白,以满足 i 的对齐要求,这样结构体 s2 的总大小为 8 字节。
输出结果通常是 struct s1 的大小: 12和 struct s2 的大小: 8 。这表明了,一个结构体的里面的类型相同,不同顺序的排列,也会使开辟的空间大小不同。
大家看看这个题,看看自己是否会了呢。