1,结构体中内存的对齐
#include "pch.h" #include <iostream> struct Test { int a; // 4 short b; // 2 char c; // 1 double d; // 8 }; int main() { Test t; t.a = 100; t.b = 200; t.c = 'c'; t.d = 10.11; printf("sizeof(Test) = %d ",sizeof(t)); std::cout << "Hello World! "; }
将结构体中数据位置换一下:
#include "pch.h" #include <iostream> struct Test { int a; // 4 double d; // 8 short b; // 2 char c; // 1 }; int main() { Test t; t.a = 100; t.b = 200; t.c = 'c'; t.d = 10.11; printf("sizeof(Test) = %d ",sizeof(t)); std::cout << "Hello World! "; }
2,结构体中含有结构体的内存对齐
该结构中占用最大空间的类型所占用的字节数,此例子中占最大空间为嵌套结构体中的double类型8字节
#include "pch.h" #include <iostream> //#pragma pack(4) struct Test { int a; // 4 short b; // 2 double d; // 8 char c; // 1 }; //#pragma pack() //能够取消自定义的对齐方式,恢复默认对齐。 struct NestTest { int i; Test t; short s; }; int main() { NestTest nt; nt.i = 10; nt.t.a = 100; nt.t.b = 200; nt.t.c = 'c'; nt.t.d = 10.11; nt.s = 8; printf("sizeof(Test) = %d ",sizeof(nt)); std::cout << "Hello World! "; }
3,含有位域的内存对齐
含有位域内存对齐
1、相邻字段类型相同,他们位宽的和不大于字段类型,存储位置紧挨着。
2、相邻字段类型相同,他们位宽的和大于字段类型,进行自身对齐,从新的存储位置开始存储。
3、相邻字段类型不同,进行自身对齐,从新的存储位置开始存储;
注意:可以无域名的进行占位(int :16)
#include "pch.h" #include <iostream> //#pragma pack(push) //#pragma pack(1) struct Test { char a:4; // char a1:4; unsigned short b:8; // unsigned short c:8; // int d : 16; }; //#pragma pack(pop) //#pragma pack() //能够取消自定义的对齐方式,恢复默认对齐。 int main() { Test t; t.a = 7; t.a1 = 6; t.b = 255; t.c = 255; t.d = 1023; printf("sizeof(Test) = %d ",sizeof(Test)); // 8 std::cout << "Hello World! "; }
每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。
程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。
对齐规则:
1、数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照 #pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。//MIN(#pragma pack,sizeof(type))
2、结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。MIN(#pragma pack,Max(#pragma pack,sizeof(type)))
3、结合1、2推断:当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。
4.各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。
5.各成员变量在存放的时候根据在结构中出现的顺序依次申请空间,同时按照上面的对齐方式调整位置,空缺的字节自动填充。
6.同时为了确保结构的大小为结构的字节边界数(即该结构中占用最大空间的类型所占用的字节数)的倍数,所以在为最后一个成员变量申请空间后,还会根据需要自动填充空缺的字节。
以下来自:https://www.cnblogs.com/yangguang-it/p/7392726.html
#pragma pack(push):
英文单词push是“压入”的意思。编译器编译到此处时将保存对齐状态(保存的是push指令之前的对齐状态)。
#pragma pack(pop):
英文单词pop是”弹出“的意思。编译器编译到此处时将恢复push指令前保存的对齐状态(请在使用该预处理命令之前使用#pragma pack(push))。
push和pop是一对应该同时出现的名词,只有pop没有push不起作用,只有push没有pop可以保持之前对齐状态(但是这样就没有使用push的必要了)。
这样就可以知道,当我们想要一个结构体按照4字节对齐时,可以使用#pragma pack(4) ,最后又想使用默认对齐方式时,可以使用#pragma pack() ;
也可以使用:
#pragma pack(push)
#pragma pack(4)
struct。。。
#pragma pack(pop)
这样在push和pop之间的结构体就可以按照pack指定的字节(这里是4字节对齐方式),而pop之后的结构体按照#pragma pack(push) 前对齐方式。
#include "pch.h" #include <iostream> #pragma pack(push) #pragma pack(1) struct Test { int a; // 4 short b; // 2 double d; // 8 char c; // 1 }; #pragma pack(pop) //#pragma pack() //能够取消自定义的对齐方式,恢复默认对齐。 struct NestTest { int i; Test t; short s; }; int main() { //NestTest nt; //nt.i = 10; //nt.t.a = 100; //nt.t.b = 200; //nt.t.c = 'c'; //nt.t.d = 10.11; //nt.s = 8; printf("sizeof(Test) = %d ",sizeof(Test)); // 15 std::cout << "Hello World! ";