70.如何获得结构成员相对于结构开头的字节偏移量

发布时间 2023-07-11 15:17:32作者: CodeMagicianT

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

参考资料来源:

程序员老吴