尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

C/C++结构体内存的问题

C/C++结构体内存的问题 1.结构体内存布局的基本规则1.1.成员顺序结构体的成员在内存中按照声明的顺序依次存放。第一个成员的地址与结构体的地址相同。struct Example { char a; // 1字节 int b; // 4字节 double c; // 8字节 short d; // 2字节 };1.2 对齐要求和结构体大小的计算结构体的大小不是简单地将所有成员的大小相加而是要考虑对齐和填充。每个基本类型如int、double、指针等都有对齐要求。对齐要求通常是该类型的大小以字节为单位或者是编译器特定的值。例如在大多数系统上int的对齐要求是4字节double的对齐要求是8字节。内存对齐:内存对齐是通过在数据间填充少量字节使数据的起始地址满足 CPU 字长32 位为 4 字节、64 位为 8 字节或数据自身大小的整数倍的内存布局规则其核心意义在于以牺牲少量内存形成内部碎片为代价既大幅提升 CPU 按访问单元批量读取内存的效率避免非对齐时多次读取、拼接数据的额外开销又能兼容不支持非对齐访问的硬件如早期 ARM 处理器以防止程序崩溃同时还能避免数据跨 CPU 访问单元存储引发的截断、乱码等问题保障数据存储的完整性与稳定性。默认对齐规则无 #pragma pack编译器默认行为数据类型分类对齐值计算规则64 位系统示例对齐值 / 大小32 位系统示例对齐值 / 大小基本数据类型对齐值 该类型的「字节大小」大小就是 sizeof 的结果char1/1short2/2int4/4double8/8同 64 位基本类型大小不变指针类型对齐值 CPU 字长64 位 832 位 4与指向的类型无关int*8/8char*8/8double*8/8int*4/4char*4/4数组类型对齐值 「数组元素的对齐值」数组整体大小不影响对齐值只影响占用空间char arr[5]1/5int arr[3]4/12double arr[2]8/16同 64 位元素对齐值不变结构体struct对齐值 其「所有成员对齐值的最大值」和成员大小无关只看成员的对齐值示例struct S {char c; double d;}对齐值 max (1,8)8同 64 位成员对齐值不变联合体union对齐值 其「所有成员对齐值的最大值」和成员大小无关只看成员的对齐值示例union U {int a; char b[5];}对齐值 max (4,1)4同 64 位成员对齐值不变嵌套结构体对齐值 该嵌套结构体「自身的对齐值」而非嵌套结构体的大小示例struct Sub {char a; double b;}// Sub对齐值 8struct S {char c; Sub s;}// S 的对齐值 max (1,8)8同 64 位计算规则:规则1:如果你有一个成员_e(大小为x字节对齐值假设也为x字节)需要加入到相对结构体起始地址0偏移y byte的位置那么需要校验y是否为对齐值x的整数倍,若不为整数倍则需加最少的n字节,使得(yn)%x 0;规则2:结构体总大小必须是最大对齐值的整数倍, 而非成员大小的最大值.规则3:若类有虚函数或者虚继承则编译器会隐式地加一个虚函数指针的大小在开头;若继承多个不同类型的父类则会继承到多个虚函数表指针. 这些虚表指针需要计入类的大小。基本示例struct Example1 { char a; // 1字节 int b; // 4字节 double c; // 8字节 }; // 由于内存对齐可能是16字节 struct Example2 { char a; // 偏移0 double b; // 偏移8不能放在1 char c; // 偏移16 }; // 总大小24字节不是17因为24是8的倍数 // 内存布局 // [a][填充7字节][b(8字节)][c][填充7字节] class MyClass { private: int a; // 4字节 double b; // 8字节 static int c; // 不计入对象大小 public: void func() {} // 函数不计入对象大小 };2.一些案例关于嵌套结构体:struct Inner { int x; // 4字节 char y; // 1字节 // 填充3字节 }; // 大小: 8字节 struct Outer { short a; // 2字节 // 填充2字节 Inner inner; // 8字节 (从4字节边界开始) char b; // 1字节 // 填充7字节 }; // 大小: 24字节3.一个特殊用法!!!对于任何一个结构体,可以获取到任何一个元素相较于结构体起点的偏移量:((struct A*)0-_element)结构体指针指向的就是结构体的起点, 同时此起点有和起始元素的地址相同;只要我们拥有结构体某一个元素的指针,那么就可以用这个指针加上偏移量得到整个结构体的指针可以用预处理指令定义一个宏offsetof:#define offsetof(TYPE, MEMBER)((size_t)((TYPE *)0)-MEMBER)4.大小端问题结构体本身并不决定字节序大端或小端也不参与字节序, 字节序是由底层的硬件架构决定的。结构体的内存布局中, 成员按照声明顺序排列考虑对齐, 但每个成员内部的字节顺序则取决于系统的字节序。大端存储Big-endian高位字节存储在低地址, 低位字节存储在高地址小端存储Little-endian低位字节存储在低地址, 高位字节存储在高地址/* 结构体内部遵循硬件平台的字节序 x86/x64架构小端序 ARM可配置通常小端序 PowerPC、SPARC大端序 网络字节序大端序 */
返回列表