C语言结构体的内存对齐问题

在C语言开发当中会遇到这样的情况:

C语言结构体的内存对齐问题
C语言结构体的内存对齐问题
 1 #include <stdio.h>
 2 
 3 struct test {
 4     int a;
 5     char b;
 6 };
 7 
 8 int main(int argc, const char * argv[])
 9 {
10     printf("%lu\n", sizeof(struct test));
11     return 0;
12 }
C语言结构体的内存对齐问题
C语言结构体的内存对齐问题

sizeof操作输出的结果是8,可是int和char类型的长度加起来只有5,那么为什么输出了8呢?

  这就牵扯到结构体的内存对齐问题,事实上,结构体中的变量在内存当中并不是以一种连续紧凑的方式存储的。

  上面这个例子是一种最简单的情况,来看一下它的内存排布:

  0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xA 0xB 0xC 0xD 0xE 0xF
0x10 a b 空位                
0x20                                

  可见,从0x15到0x18都是空位,为什么要这样存储呢?因为计算机字长为4,处理结构体变量时,需要一次读入32位,也就是4个字节,那么假定两个结构体变量a和b,a从0x10开始,b从0x15开始的话,则需要两次寻址,第一次是读出0x14到0x17,取出后三位,第二次是从0x18到0x1B,取出第一位,然后做位运算,由于变量处理很频繁,这样就增加了性能的开销,那么只能采取用空间换时间的策略了。

  假设有两个结构体变量,那么内存排布是这样的:

  0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xA 0xB 0xC 0xD 0xE 0xF
0x10 a b 空位 a b 空位
0x20                                

  这便是内存对齐的第一个方面——结构体的末尾如果没有对齐,则会留出空位来,为排在它前后的变量提供寻址上的便利。

  事实上,结构体的大小,必然是其中占用空间最大的类型的长度的整数倍。

  接下来改变一下我们的结构体:

C语言结构体的内存对齐问题
1 struct test {
2     char b;
3     int a;
4 };
C语言结构体的内存对齐问题

 

它的长度同样是8,内存排布如下:

  0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xA 0xB 0xC 0xD 0xE 0xF
0x10 b 空位 a                
0x20                                

  同样基于上面提到的原因,如果将a放在0x11的位置,需要两次寻址。那么,结构体内存排列的一个重要原则就是要得到最少的寻址次数,显然,为了方便找到int型的a,需要在b后面空出3个字节的空间来。

  下面举一个稍微复杂一点的例子:

C语言结构体的内存对齐问题
C语言结构体的内存对齐问题
1 struct test {
2     char a;
3     int b;
4     char c;
5     char d;
6     double e;
7     char f;
8 };
C语言结构体的内存对齐问题
C语言结构体的内存对齐问题

 

它的长度是32,看一下内存排列:

  0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xA 0xB 0xC 0xD 0xE 0xF
0x10 a 空位 b c d 空位
0x20 e f 空位

  为了让变量b寻址方便,在a的后面空出了3个字节,而c和d无论如何都要寻址一次,所以顺序排下去就可以了,而e长度为8,按说可以从0x1C开始排,但是这里需要和类型本身的长度8进行对齐,则排在了0x20的位置,于是乎d的后面又空出了6个字节的空间,最后f排在e的后面,之后为了结构体本身和最长类型的长度8对齐,后面又留出了7个字节的空位。

  显而易见结构体当中变量的顺序是会影响存储空间的,在设计结构体的时候需要进行优化,比如将上面的结构体改写成下面的形式可以节省空间:

C语言结构体的内存对齐问题
C语言结构体的内存对齐问题
1 struct test {
2     char a;
3     char c;
4     char d;
5     char f;
6     int b;
7     double e;
8 };
C语言结构体的内存对齐问题
C语言结构体的内存对齐问题

 

这种排列只占用16字节,内存如下:

  0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xA 0xB 0xC 0xD 0xE 0xF
0x10 a c d f b e
0x20                                

  可见,内存对齐是一种空间换时间的手段,当然,为了节约内存,可以通过如下代码令结构体紧凑排列:

C语言结构体的内存对齐问题
1 #pragma pack(1)
C语言结构体的内存对齐问题

C语言结构体的内存对齐问题,布布扣,bubuko.com

C语言结构体的内存对齐问题

上一篇:初识JavaScript 1


下一篇:spring 容器生成bean的3中方式