一个很重要的参数
#pragma pack(n) 数据边界对齐方式: 以如下结构为例: struct test { char a; WORD b; DWORD c; char d; }test; 在Windows默认结构大小: sizeof(test) = 4+4+4+4=16; 与#pragma pack(4)一样 若设为 #pragma pack(1), 则结构大小: sizeof(struct) = 1+2+4+1=8; 若设为 #pragma pack(2), 则结构大小: sizeof(struct) = 2+2+4+2=10; 在#pragma pack(1)时:空间是节省了,但访问速度降低了; ============================================================ 结构体对齐的具体含义 例: #pragma pack(4) class TestB { public: int aa; char a; short b; char c; }; int nSize = sizeof(TestB); 这里nSize结果为12,在预料之中。 现在去掉第一个成员变量为如下代码: #pragma pack(4) class TestC { public: char a; short b; char c; }; int nSize = sizeof(TestC); 按照正常的填充方式nSize的结果应该是8,为什么结果显示nSize为6呢? 事实上,很多人对#pragma pack的理解是错误的。 #pragma pack规定的对齐长度,实际使用的规则是: 结构,联合,或者类的数据成员,第一个放在偏移为0的地方,以后每个数据成员的对齐,按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。 也就是说,当#pragma pack的值等于或超过所有数据成员长度的时候,这个值的大小将不产生任何效果。 而结构整体的对齐,则按照结构体中最大的数据成员 和 #pragma pack指定值 之间,较小的那个进行。 具体解释 #pragma pack(4) class TestB { public: int aa; //第一个成员,放在[0,3]偏移的位置, char a; //第二个成员,自身长为1,#pragma pack(4),取小值,也就是1,所以这个成员按一字节对齐,放在偏移[4]的位置。 short b; //第三个成员,自身长2,#pragma pack(4),取2,按2字节对齐,所以放在偏移[6,7]的位置。 char c; //第四个,自身长为1,放在[8]的位置。 }; 这个类实际占据的内存空间是9字节 类之间的对齐,是按照类内部最大的成员的长度,和#pragma pack规定的值之中较小的一个对齐的。 所以这个例子中,类之间对齐的长度是min(sizeof(int),4),也就是4。 9按照4字节圆整的结果是12,所以sizeof(TestB)是12。 如果 #pragma pack(2) class TestB { public: int aa; //第一个成员,放在[0,3]偏移的位置, char a; //第二个成员,自身长为1,#pragma pack(4),取小值,也就是1,所以这个成员按一字节对齐,放在偏移[4]的位置。 short b; //第三个成员,自身长2,#pragma pack(4),取2,按2字节对齐,所以放在偏移[6,7]的位置。 char c; //第四个,自身长为1,放在[8]的位置。 }; //可以看出,上面的位置完全没有变化,只是类之间改为按2字节对齐,9按2圆整的结果是10。 //所以 sizeof(TestB)是10。 最后看原贴: 现在去掉第一个成员变量为如下代码: #pragma pack(4) class TestC { public: char a;//第一个成员,放在[0]偏移的位置, short b;//第二个成员,自身长2,#pragma pack(4),取2,按2字节对齐,所以放在偏移[2,3]的位置。 char c;//第三个,自身长为1,放在[4]的位置。 }; //整个类的大小是5字节,按照min(sizeof(short),4)字节对齐,也就是2字节对齐,结果是6 //所以sizeof(TestC)是6。 C编译器的缺省字节对齐方式(自然对界)
在结构中,编译器为结构的每个成员按其自然对界(alignment)条件分配空间。各个成员按照它们被声明的顺序在内存中顺序存储(成员之间可能有插入的空字节),第一个成员的地址和整个结构的地址相同。 C编译器缺省的结构成员自然对界条件为“N字节对齐”,N即该成员数据类型的长度。如int型成员的自然对界条件为4字节对齐,而double类型的结构成员的自然对界条件为8字节对齐。若该成员的起始偏移不位于该成员的“默认自然对界条件”上,则在前一个节面后面添加适当个数的空字节。 C编译器缺省的结构整体的自然对界条件为:该结构所有成员中要求的最大自然对界条件。若结构体各成员长度之和不为“结构整体自然对界条件的整数倍,则在最后一个成员后填充空字节。 例子1(分析结构各成员的默认字节对界条界条件和结构整体的默认字节对界条件): struct Test { char x1; // 成员x1为char型(其起始地址必须1字节对界),其偏移地址为0 char x2; // 成员x2为char型(其起始地址必须1字节对界,其偏移地址为1 float x3; // 成员x3为float型(其起始地址必须4字节对界),编译器在x2和x3之间填充了两个空字节,其偏移地址为4 char x4; // 成员x4为char型(其起始地址必须1字节对界),其偏移地址为8 };
例子2: #include <stdio.h> //#pragma pack(2) typedef struct { int aa1; //4个字节对齐 1111 char bb1;//1个字节对齐 1 short cc1;//2个字节对齐 011 char dd1; //1个字节对齐 1 } testlength1; int length1 = sizeof(testlength1); //4个字节对齐,占用字节1111 1011 1000,length = 12 typedef struct { char bb2;//1个字节对齐 1 int aa2; //4个字节对齐 01111 short cc2;//2个字节对齐 11 char dd2; //1个字节对齐 1 } testlength2; int length2 = sizeof(testlength2); //4个字节对齐,占用字节1011 1111 1000,length = 12 typedef struct { char bb3; //1个字节对齐 1 char dd3; //1个字节对齐 1 int aa3; //4个字节对齐 001111 short cc23//2个字节对齐 11 } testlength3; int length3 = sizeof(testlength3); //4个字节对齐,占用字节1100 1111 1100,length = 12 typedef struct { char bb4; //1个字节对齐 1 char dd4; //1个字节对齐 1 short cc4;//2个字节对齐 11 int aa4; //4个字节对齐 1111 } testlength4; int length4 = sizeof(testlength4); //4个字节对齐,占用字节1111 1111,length = 8 int main(void) { printf("length1 = %d.\n",length1); printf("length2 = %d.\n",length2); printf("length3 = %d.\n",length3); printf("length4 = %d.\n",length4); return 0; } 改变缺省的对界条件(指定对界)
1、数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。 2、结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。 结合1、2推断:当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。 因此,当使用伪指令#pragma pack (2)时,Test结构体的大小为8,内存布局为11 11 11 10。
#pragma pack(8)
sizeof(s2)的结果为24。S1的内存布局为1100 1111,S2的内存布局为1000 1100 1111 0000 1111 1111。 例子: #include <stdio.h> #pragma pack(2) typedef struct { int aa1; //2个字节对齐 1111 char bb1;//1个字节对齐 1 short cc1;//2个字节对齐 011 char dd1; //1个字节对齐 1 } testlength1; int length1 = sizeof(testlength1); //2个字节对齐,占用字节11 11 10 11 10,length = 10 typedef struct { char bb2;//1个字节对齐 1 int aa2; //2个字节对齐 01111 short cc2;//2个字节对齐 11 char dd2; //1个字节对齐 1 } testlength2; int length2 = sizeof(testlength2); //2个字节对齐,占用字节10 11 11 11 10,length = 10 typedef struct { char bb3; //1个字节对齐 1 char dd3; //1个字节对齐 1 int aa3; //2个字节对齐 11 11 short cc23//2个字节对齐 11 } testlength3; int length3 = sizeof(testlength3); //2个字节对齐,占用字节11 11 11 11,length = 8 typedef struct { char bb4; //1个字节对齐 1 char dd4; //1个字节对齐 1 short cc4;//2个字节对齐 11 int aa4; //2个字节对齐 11 11 } testlength4; int length4 = sizeof(testlength4); //2个字节对齐,占用字节11 11 11 11,length = 8 int main(void) { printf("length1 = %d.\n",length1); printf("length2 = %d.\n",length2); printf("length3 = %d.\n",length3); printf("length4 = %d.\n",length4); return 0; } 另外,还有如下的一种方式: · __attribute((aligned (n))),让所作用的结构成员对齐在n字节自然边界上。如果结构中有成员的长度大于n,则按照最大成员的长度来对齐。 · __attribute__ ((packed)),取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。
http://bbs.sciencenet.cn/home.php?mod=space&uid=47522&do=blog&id=503874 |
|