【C语言】字节对齐(内存对齐)

  

1.  对齐原则:

【原则1】数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。

【原则2】结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。

【原则3】结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。

备注:数组成员按长度按数组类型长度计算,如char t[9],在第1步中数据自身长度按1算,累加结构体时长度为9;第2步中,找最大数据长度时,如果结构体T有复杂类型成员A,该A成员的长度为该复杂类型成员A的最大成员长度。

小结:当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。


 【注意】(对齐位数跟处理器位数和编译器都有关)VS, VC等编译器默认是#pragma pack(8),所以测试我们的规则会正常;注意gcc默认是#pragma pack(4),并且gcc只支持1,2,4对齐。套用三原则里计算的对齐值是不能大于#pragma pack指定的n值。

2. 自然对齐存放变量的地址要是该变量数据类型大小的整数倍。如:存放int型数据的地址一定要是4的倍数,存放short型数据的地址一定要是2的倍数。

 

3. 改变缺省的对界条件(指定对界):

  • 使用伪指令#pragma pack (n),C编译器将按照n个字节对齐。
  • 使用伪指令#pragma pack(),取消自定义字节对齐方式。

举例一

例1:

1 2 3 4 5 6 7 8 9 10 #pragma pack(1) struct AA { ????int a;???//长度4 < 1 按1对齐;偏移量为0;存放位置区间[0,3] ????char b;??//长度1 = 1 按1对齐;偏移量为4;存放位置区间[4] ????short c;?//长度2 > 1 按1对齐;偏移量为5;存放位置区间[5,6] ????char d;??//长度1 = 1 按1对齐;偏移量为6;存放位置区间[7] ????//整体存放在[0~7]位置区间中,共八个字节。 }; #pragma pack()

 结果:8个字节

 

例2:

1 2 3 4 5 6 7 8 9 #pragma pack(2) struct AA { ????int a;???//长度4 > 2 按2对齐;偏移量为0;存放位置区间[0,3] ????char b;??//长度1 < 2 按1对齐;偏移量为4;存放位置区间[4] ????short c;?//长度2 = 2 按2对齐;偏移量要提升到2的倍数6;存放位置区间[6,7] ????char d;??//长度1 < 2 按1对齐;偏移量为7;存放位置区间[8];共九个字节 }; #pragma pack()

 结果:10个字节

 

例3:

1 2 3 4 5 6 7 8 9 #pragma pack(4) struct AA { ????int a;???//长度4 = 4 按4对齐;偏移量为0;存放位置区间[0,3] ????char b;??//长度1 < 4 按1对齐;偏移量为4;存放位置区间[4] ????short c;?//长度2 < 4 按2对齐;偏移量要提升到2的倍数6;存放位置区间[6,7] ????char d;??//长度1 < 4 按1对齐;偏移量为7;存放位置区间[8];总大小为9 }; #pragma pack()

 结果:12个字节

 

例4:

1 2 3 4 5 6 7 8 9 #pragma pack(8) struct AA { ????int a;???//长度4 < 8 按4对齐;偏移量为0;存放位置区间[0,3] ????char b;??//长度1 < 8 按1对齐;偏移量为4;存放位置区间[4] ????short c;?//长度2 < 8 按2对齐;偏移量要提升到2的倍数6;存放位置区间[6,7] ????char d;??//长度1 < 8 按1对齐;偏移量为7;存放位置区间[8],总大小为9 }; #pragma pack()

 结果:12个字节  

 

例5:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 struct EE??//8个字节对齐 { ????int a;??????//长度4 < 8 按4对齐;偏移量为0;存放位置区间[0,3] ????char b;?????//长度1 < 8 按1对齐;偏移量为4;存放位置区间[4] ????short c;????//长度2 < 8 按2对齐;偏移量由5提升到6;存放位置区间[6,7]   ????struct FF???//结构体内部最大元素为int,由于偏移量为8刚好是4的整数倍,所以从8开始存放接下来的struct FF ????{ ????????int a1;?????//长度4 < 8 按4对齐;偏移量为8;存放位置区间[8,11] ????????char b1;????//长度1 < 8 按1对齐;偏移量为12;存放位置区间[12] ????????short c1;???//长度2 < 8 按2对齐;偏移量为13,提升到2的倍数14;存放位置区间[14,15] ????????char d1;????//长度1 < 8 按1对齐;偏移量为16;存放位置区间[16] ????};??????????????//整体对齐系数 = min((max(int,short,char), 8) = 4,将内存大小由17补齐到4的整数倍20 ????  ????char d;?????????//长度1 < 8 按1对齐;偏移量为21;存放位置区间[21] ????????????????????//整体对齐系数 = min((max(int,short,char), 8) = 4,将内存大小由21补齐到4的整数倍24 };

【C语言】字节对齐(内存对齐) - 文章图片

 

1 2 3 4 5 6 7 8 9 10 11 12 13 struct B { ????char e[2];??????//长度1 < 8 按2对齐;偏移量为0;存放位置区间[0,1] ????short h;????????//长度2 < 8 按2对齐;偏移量为2;存放位置区间[2,3] ????????????????????//结构体内部最大元素为double,偏移量为4,提升到8,所以从8开始存放接下来的struct A ????struct A ????{ ????????int a;??????//长度4 < 8 按4对齐;偏移量为8;存放位置区间[8,11] ????????double b;???//长度8 = 8 按8对齐;偏移量为12,提升到16;存放位置区间16,23] ????????float c;????//长度4 < 8,按4对齐;偏移量为24,存放位置区间[24,27] ????}; ????//整体对齐系数 = min((max(int,double,float), 8) = 8,将内存大小由28补齐到8的整数倍32 };

【C语言】字节对齐(内存对齐) - 文章图片

举例二

代码1:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include <stdio.h> 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; } 

VS2017输出结果:

【C语言】字节对齐(内存对齐) - 文章图片

 

 代码2:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 #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; }

VS2017输出结果:

【C语言】字节对齐(内存对齐) - 文章图片

  

代码3:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include<iostream> using namespace std;   typedef struct bb { ????int id;?????????????//[0]....[3] ????double weight;??????//[8].....[15]      原则1 ????float height;???????//[16]..[19],总长要为8的整数倍,补齐[20]...[23]     原则3 }BB;   typedef struct aa { ????char name[2];????//[0],[1] ????int  id;?????????//[4]...[7]          原则1 ????double score;????//[8]....[15]     ????short grade;?????//[16],[17]         ????BB b;????????????//[24]......[47]          原则2 }AA;   int main() { ????AA a; ????cout <<?sizeof(a) <<?" " <<?sizeof(BB) << endl; ????return 0; }

VS2017输出结果: 48 24

 

代码4:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include<iostream> using namespace std;   #pragma pack(2) typedef struct bb { ????int id;???????????? ????double weight;????? ????float height;?????? }BB;   typedef struct aa { ????char name[2];??? ????int  id;??????? ????double score;??? ????short grade;???       ????BB b;?????????? }AA;   int main() { ????AA a; ????cout <<?sizeof(a) <<?" " <<?sizeof(BB) << endl; ????return 0; }

VS2017输出结果:32 16  

相关文章