C的结构体字节对齐

作用

结构体对齐主要是为了提高处理器读取内存的效率。举个例子来说,假设一个处理器每次读写内存都是从4字节的倍数处读写,并且每次能读写4字节的数据,如果一个int型数据起始地址在4字节倍数处,那么一次CPU操作就可以取出这个int型数据,否则至少要进行两次读取操作,并需要进行位操作才能拼凑出这个int型数据。所以,对于包含多个成员变量的结构体来说,要在不同的变量之间填充空白字节以使每个字段的首字节保持对齐,也就是所谓的结构体对齐。可见,结构体对齐是一种以空间换时间的优化方式。
需要注意的是,在Linux与Windows之间,32位OS和64位OS之间,甚至GCC和VC++之间,结构体的对齐方式都是有区别的,所以在不同环境下sizeof(struct)操作得到的结果经常是不同的,本文的测试环境基于32位Ubuntu,GCC4.7。

规则

对齐值

首先,为了方便阐述,将对齐值分为以下几种:
1)基本数据自身对齐值:基本数据类型的自身对齐值,一般由编译器及系统决定;
2)结构体自身对齐值:取决于结构体成员中自身对齐值的最大值;
3)指定对齐值:通过#pragma pack(n)宏指定的对齐值;
4)有效对齐值:取决于自身对齐值和指定对齐值中的较小值。

对于每种基本数据类型,都有一个自身对齐值,而结构体的自身对齐值将取成员中自身对齐值最大的
32位OS下Linux/GCC与Windwos/VC++中基本数据类型自身对齐值(来自Wiki)
























































类型 Windows/VC++ Linux/GCC
长度 对齐值 长度 对齐值
char 1 1 1 1
short 2 2 2 2
int,long,float,pointer 4 4 4 4
double 8 8 8 4
long double 8 8 12 4
long long 8 8 8 8

以下几种基本数据类型在64位OS下自身对齐值有所不同









































类型 Windows/VC++ Linux/GCC
长度 对齐值 长度 对齐值
long 8 8 8 8
double 8 8 8 8
long double 8 8 16 16
pointer 8 8 8 8

另外,有些编译器可以通过#pragma pack(n)宏来指定结构体的对齐方式,n的取值范围是{1,2,4,8,16},(GCC中默认是4,VC++中默认是8)基本数据类型的有效对齐值将取n和自身对齐值中较小的,而结构体的有效对齐值将取决于n和结构体自身对齐值中较小的,也就是说如果前面算出来结构体的自身对齐值是4,那么指定n为8或者16都是没用的。

计算方法

结构体大小的计算方法遵循以下两条规则:
1)假设结构体的起始位置为0,结束位置为n,n必须是结构体有效对齐值的倍数。
2)假设某成员的起始对齐值是m,m必须是该成员有效对齐值的倍数。

样例

样例一

1
2
3
4
5
6
typedef struct _C{
int a;
char b;
int* c;
short d;
}C;

首先,int,char,pointer,short的自身对齐值分别为4,1,4,2,所以结构体自身对齐值为4。
a起始位置0,结束位置4,0%4=0,占4个字节。
b起始位置4,结束位置5,4%1=0,占1个字节。
c起始位置8,结束位置12,8%4=0,占4个字节,需要在前面填充3个字节。
d起始位置12,结束位置14,12%4=0,占2个字节。
最后结构体结束位置16,16%4=0,需要在d后填充2个字节,结构体共占16个字节。

样例二

1
2
3
4
5
6
7
#pragma pack(2)
typedef struct _C{
int a;
char b;
int *c
short d;
}C;

该结构体与样例一中相同,不同的是指定了对齐值为2,那么int,char,pointer,short的有效对齐值变为2,1,2,2,结构体有效对齐值为2。
a起始位置0,结束位置4,0%2=0,占4个字节。
b起始位置4,结束位置5,4%1=0,占1个字节。
c起始位置6,结束位置10,6%2=0,占4个字节,需要在前面填充1个字节。
d起始位置10,结束位置12,12%4=2,占2个字节。
最后结构体结束位置12,12%2=0,结构体共占12个字节。

样例三

1
2
3
4
5
6
typedef struct _C{
int a;
int *b;
short c;
char d;
}C;

该结构体与样例一中相同,只是更改了成员的排列方式。
a起始位置0,结束位置4,0%4=0,占4个字节。
b起始位置4,结束位置8,4%4=0,占4个字节。
c起始位置8,结束位置10,8%2=0,占2个字节。
d起始位置10,结束位置11,10%1=0,占1个字节。
最后结构体结束位置12,12%4=0,需要在d后填充1个字节,结构体共占12个字节。
可以看到,通过更改结构体成员的排列方式,可以节省内存空间,所以往往要精心设计结构体排列来达到节省内存的目的。

引用

http://blog.csdn.net/han_xiaoyang/article/details/11596001
http://en.wikipedia.org/wiki/Data_structure_alignment

文章目录
  1. 1. 作用
  2. 2. 规则
    1. 2.1. 对齐值
    2. 2.2. 计算方法
  3. 3. 样例
    1. 3.1. 样例一
    2. 3.2. 样例二
    3. 3.3. 样例三
  4. 4. 引用