对于大多数的程序员来说,内存对齐基本上是透明的,这是编译器该干的活,编译器为程序中的每个数据单元安排在合适的位置上,从而导致了相同的变量,不同声明顺序的结构体大小的不同。
那么编译器为什么要进行内存对齐呢?主要是为了性能和平台移植等因素,编译器对数据结构进行了内存对齐。
为了分析造成这种现象的原因,我们不得不提及内存对齐的3大规则:
- 对于结构体的各个成员,第一个成员的偏移量是0,排列在后面的成员其当前偏移量必须是当前成员类型的整数倍;
- 结构体内所有数据成员各自内存对齐后,结构体本身还要进行一次内存对齐,保证整个结构体占用内存大小是结构体内最大数据成员的最小整数倍;
- 如程序中有#pragma pack(n)预编译指令,则所有成员对齐以n字节为准(即偏移量是n的整数倍),不再考虑当前类型以及最大结构体内类型。
首先我们测试在32位编译方式产生的结果:
首先在Linux的命令行模式下新建一个structsize.c源文件,代码内容如下
#include<stdio.h>
#include<stdlib.h>
struct size{
char c;
int i;
long l;
char *pointer;
};
int main()
{
struct size s;
printf("size:%d\n",sizeof(s));
return 0;
}
在Linux打开一个新的终端,然后采用32位的方式编译
gcc -m32 structsize.c -o size32.o -Wall
./size32.o
程序运行的输出结果为:
size:16
在32位的编译方式下,char类型的大小为1个字节,int与long及指针的大小均为4个字节,因为内存使用中存在对齐,char类型的变量实际上占用了4个字节。
当我们把代码修改为适合在64位平台上运行时
#include<stdio.h>
#include<stdlib.h>
struct size{
char c;
int i;
long l;
char *pointer;
};
int main()
{
struct size s;
printf("size:%ld\n",sizeof(s));
return 0;
}
编译并运行
gcc structsize.c -o size64.o -Wall
./size64.o
得到程序运行结果为32,这是由于结构体中的长整型和指针的大小都是8个字节,1个字节长的char和4个字节长的int都被补充到8个字节,因此输出结果为32