转载

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必须是该成员有效对齐值的倍数。

样例

样例一

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个字节。

样例二

#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个字节。

样例三

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

原文  http://vimersu.win/blog/2014/01/11/struct-alignment/
正文到此结束
Loading...