起因
朋友最近发来一段代码,自己刚看到代码懵了一会儿,特此记录一下
代码如下:
struct Base
{
uint8_t a;
uint32_t b;
};
int main()
{
auto n = (intptr_t)(&((Base*)0)->b);
cout << n << endl;
}
上面定义了一个结构体类型Base,main函数里面输出的值是多少?起初自己认为将常量0强转为Base*,再访问成员变量b,是一个ub操作,n的值无意义,后来发现输出n的值为1。
经过了解才明白这个是获取结构体成员偏移量常用的手法,上面代码将常量0转换为指针再访问b,确实是非法的操作,不过前面的取地址符其实是合法的,因为转换后的首地址为0,取成员变量b的地址,就等于b的偏移量,而uint8_t是1个字节,所以b的偏移量是1(当然这里是没有考虑内存对齐的结果,如果考虑内存对齐的话,b的偏移量就是4了)。
最后
在项目里,如果我们有许多计算结构体成员偏移量的情况,可以定义一个宏来到达我们的目的
例如:
#define OFFSET(TYPE,MEMBER) (intptr_t)(&((TYPE*)0)->MEMBER)