考虑以下代码:
#include <iostream>
struct bar {
double a = 1.0;
int b = 2;
float c = 3.0;
};
void callbackFunction(int* i) {
auto myStruct = reinterpret_cast<bar*>(i) - offsetof(bar, b);
std::cout << myStruct->a << std::endl;
std::cout << myStruct->b << std::endl;
std::cout << myStruct->c << std::endl;
//do stuff
}
int main() {
bar foo;
callbackFunction(&foo.b);
return 0;
}
我必须定义一个回调函数,并且我想在该函数中使用一些附加信息。我定义了自己的结构并将成员的地址传递给函数。在函数中,我想通过强制转换“检索”整个结构,但指针似乎不匹配,并且得到错误的结果。我想我在铸造时做错了什么,但我不确定是什么?
你缺少一个演员来完成这项工作。您需要在减去偏移量之前转换为字节类型,然后重新转换回bar*
。原因是宏offsetof
以字节数形式返回偏移量。当您进行指针算术时,减法和加法根据指向类型的大小进行计算。我们举个例子:
假设您有一个bar
实例,命名为b
位于地址 0x100h 处。假如说sizeof(double) == 8
, sizeof(int) == 4
and sizeof(float) == 4
, then sizeof(bar) == 16
你的结构及其成员在内存中看起来像这样:
b @ 0x100h
b.a @ 0x100h
b.b @ 0x108h
b.c @ 0x10Ch
offsetof(bar,b)
将等于8
。您的原始代码表示“将 0x108h 视为指向类型的结构”bar
。然后给我bar
结构体地址0x108h - 8 * sizeof(bar)
,或者具体来说:0x108h - 0x80h = 88h。希望这个例子能够说明为什么原始代码执行错误的计算。
这就是为什么您需要告诉编译器您想要将地址作为字节减去,以获得结构中第一个成员的正确地址。
解决方案看起来像这样:
bar* owner = reinterpret_cast<bar*>(reinterpret_cast<char *>(i) - offsetof(bar, b));
您应该非常小心的一件事:这是合法的only if bar
is 标准布局。您可以使用模板std::is_standard_layout<bar>::value
进行静态断言以验证您没有意外调用 UB。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)