本文主要是介绍结构体对齐的具体含义(#pragma pack的用法),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
转载自: http://www.mscenter.edu.cn/blog/mingge/archive/2005/12/10/7655.html 朋友帖了如下一段代码: #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的理解是错误的。 关于 struct 的使用方法 struct是一种复合数据类型,其构成元素既可以是基本数据类型(如int、long、float等)的变量,也可以是一些复合数据类型(如array、struct、union等)的数据单元。对于结构体,编译器会自动进行成员变量的对齐,以提高运算效率。缺省情况下,编译器为结构体的每个成员按其 自然对界( natural alignment )条件分配空间。各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。 自然对界是指按结构体的成员中size最大的成员对齐。 #pragma pack 规定的对齐长度,实际使用的规则是: 结构,联合,或者类的数据成员,第一个放在偏移为0的地方,以后每个数据成员的对齐, 按照 #pragma pack 指定的数值和结构体的自然对齐长度中比较小的那个进行。 也就是说,当#pragma pack的值等于或超过所有数据成员长度的时候,这个值的大小将不产生任何效果。 结构体的对齐,按照结构体中size最大的数据成员和#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。 在Linux下面就是 #define __PACKED_ATTR __attribute__ ((__packed__)) typedef struct { char p[3] __PACKED_ATTR; long i __PACKED_ATTR; } test ; typedef struct { char p[3]; long i; } test1; gcc test.c 编译后,它们的大小就是7,8了 windows下面默认的是 #pragma pack ( 8 ) 因为编译器在编译时会对程序进行优化,以便加快访问速度,所以一般都会按照2的倍数进行字节对齐。用这个宏就是为了防止编译器对结构的定义进行对齐。 #pragma(push,n)用来设置警告消息的等级 |
这篇关于结构体对齐的具体含义(#pragma pack的用法)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!