70.如何获得结构成员相对于结构开头的字节偏移量
70.如何获得结构成员相对于结构开头的字节偏移量
使用<stddef.h>头文件中的,offsetof宏。
举个例子:
#include <iostream>
#include <stddef.h>
using namespace std;
struct S
{
int x;
char y;
int z;
double a;
};
int main()
{
cout << offsetof(S, x) << endl; // 0
cout << offsetof(S, y) << endl; // 4
cout << offsetof(S, z) << endl; // 8
cout << offsetof(S, a) << endl; // 16
return 0;
}
在Visual Studio 2022(X64) + Win10 下的输出情况如下
cout << offsetof(S, x) << endl; // 0
cout << offsetof(S, y) << endl; // 4
cout << offsetof(S, z) << endl; // 8
cout << offsetof(S, a) << endl; // 16 这里是 16的位置,因为 double是8字节,需要找一个8的倍数对齐,
当然了,如果加上 #pragma pack(4) 指定4字节对齐方式就可以了。
#pragma pack(4)
struct S
{
int x;
char y;
int z;
double a;
};
void test02()
{
cout << offsetof(S, x) << endl; // 0
cout << offsetof(S, y) << endl; // 4
cout << offsetof(S, z) << endl; // 8
cout << offsetof(S, a) << endl; // 12
}
S结构体中各个数据成员的内存空间划分如下所示,需要注意内存对齐
参考资料来源:
阿秀
1.什么是内存对齐??
内存对齐可以提高CPU的内存访问效率,因为CPU在读取内存时是按照一块一块的方式进行读取,每块的大小由内存读取粒度确定,通常为2、4、8或16个字节。
1.硬件存储和读取
一个内存是由若干个黑色的内存颗粒构成的。每一个内存颗粒叫做一个chip。每个chip内部,是由8个bank组成的。构造如下图:
每一个bank是一个二维平面上的矩阵。矩阵中每一个元素中都是保存了1个字节,也就是8个bit。
那么对于我们在应用程序中内存地址连续的8个字节,例如0x0000-0x0007,是从位于bank上的呢?直观感觉,应该是在第一个bank上吗?其实不是的,程序员视角看起来连续的0x0000-0x0007,实际上位于8个bank中,每一个bank只保存了一个字节。在物理上,他们并不连续。下图很好地阐述了实际情况。
结论:一个int会被存放在连续的bank上,而不是分别存在四个颗粒上。
2.对齐规则
1.每个特定平台上的编译器都有自己的默认“对齐系数”#pragma pack(show)可以查看
2.有效对齐值:是给定值#pragma pack(n)和结构体中最长数据类型长度中较小的那个。有效对齐值也叫对齐单位。
3.结构体第一个成员变量的偏移量(offset)为0,以后每个数据成员的起始位置要从自身大小的整数倍开始存储
4.结构体的总大小为:若没有设定对齐字节数,则最大成员为对齐字节数。若有设定对齐字节数,则对齐字节数为:min(最大成员,设定的对齐字节数)的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。
所占用字节数分别为:40 36 40
参考资料来源:
程序员老吴