分类: LINUX
2010-03-15 18:16:55
缺省的对齐方式。
在结构中,编译器为结构的每个成员按其自然对界(alignment)条件分配空间;各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间。
例如,下面的结构各成员空间分配情况。
struct test {
char x1;
short x2;
float x3;
char x4;
};
结构的第一个成员x1,其偏移地址为0,占据了第1个字节。第二个成员x2为short类型,其起始地址必须2字节对界,因此,编译器在x2和x1之间
填充了一个空字节。结构的第三个成员x3和第四个成员x4恰好落在其自然对界地址上,在它们前面不需要额外的填充字节。在test结构中,成员x3要求4
字节对界,是该结构所有成员中要求的最大对界单元,因而test结构的自然对界条件为4字节,编译器在成员x4后面填充了3个空字节。整个结构所占据空间
为12字节。
字节对齐的细节和编译器实现相关,但一般而言,满足三个准则:
1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);
3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。
注意的是:
基 本类型是指前面提到的像char、short、int、float、double这样的内置数据类型,这里所说的“数据宽度”就是指其sizeof的大 小。由于结构体的成员可以是复合类型,比如另外一个结构体,所以在寻找最宽基本类型成员时,应当包括复合类型成员的子成员,而不是把复合成员看成是一个整 体。但在确定复合类型成员的偏移位置时则是将复合类型作为整体看待。
更改C编译器的缺省分配策略
一般地,可以通过下面的方法改变缺省的对界条件:
? 使用伪指令#pragma pack ([n])
#pragma pack ([n])伪指令允许你选择编译器为数据分配空间所采取的对界策略。
例如,在使用了#pragma pack (1)伪指令后,test结构各成员的空间分配情况就是按照一个字节对齐了,格式如下:
#pragma pack(push) //保存对齐状态
#pragma pack(1)
//定义你的结构
//…………
#pragma pack(pop)
附:c中各基本类型的字节数
类型名称 |
字节数 |
其它称呼 |
值的范围 |
int | * | signed, signed int |
根据操作系统而定 |
unsigned int | * | unsigned | 根据操作系统而定 |
__int8 | 1 | char, signed char |
-128 to 127 |
__int16 | 2 | short, short int, signed short int |
-32,768 to 32,767 |
__int32 | 4 | signed, signed int |
-2,147,483,648 to 2,147,483,647 |
__int64 | 8 | none | -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 |
char | 1 | signed char | -128 to 127 |
unsigned char | 1 | none | 0 to 255 |
short | 2 | short int, signed short int |
-32,768 to 32,767 |
unsigned short | 2 | unsigned short int | 0 to 65,535 |
long | 4 | long int, signed long int |
-2,147,483,648 to 2,147,483,647 |
unsigned long | 4 | unsigned long int | 0 to 4,294,967,295 |
enum | * | none | 与int相同 |
float | 4 | none | 3.4E +/- 38 (7 digits) |
double | 8 | none | 1.7E +/- 308 (15 digits) |
long double | 10 | none | 1.2E +/- 4932 (19 digits) |
C++的基本类型:
类型 字节数