有一个指向成员的指针,你需要得到这个地址的一个数字表示,也就是一个偏移量。在这样的代码中:
struct Foo
{
int Bar;
};
auto pointer_to_member = &Foo::Bar;
auto offset_of_member = reinterpret_cast<uintptr_t>(pointer_to_member); // ошибка
我的 VisualC++ 写了一个错误:
错误 C2440:
reinterpret_cast
无法转换int Foo::Bar *
为uintptr_t
问题。这不是标准吗?以及如何在没有offsetof
指向成员的现成指针的情况下获得偏移量?
你的方法是不可能的。打开offsetof文档并阅读
在 gcc 中是这样完成的
MSVC 是对的,你不能那样做。
它也不能通过 offsetof 工作,因为它只适用于字段名称,而不适用于指向它们的指针。
offsetof(Foo, *pointer_to_member)
由于this的实现特性,它可能适用于 MSVCoffsetof
。但它不符合标准,至少在 GCC 上不起作用。唯一完全标准的方法(据我所知)是创建一个对象,向它应用一个字段指针,然后从字段地址中减去对象地址:
更方便的选择是从指向
uintptr_t
via中的字段的指针进行类型双关memcpy()
:该标准不保证(据我所知,再次)将字段指针存储为偏移量,但这应该适用于所有主要编译器。
如果手头没有现成的物品
Foo
,我会使用这种方法。不要尝试
reinterpret_cast<uintptr_t &>(pointer_to_member)
,或通过类型双关语union
。由于违反了严格的别名,两者都是未定义的行为。这是另一种方式。看起来不错,但由于无效的指针访问而导致未定义的行为。
(虽然
offsetof
MSVC 中的默认实现使用了类似的技巧。)是的,这种转换不是标准的。对于指向成员的指针,没有定义到整数运算的转换。事实上,指向成员的指针并不是经典意义上的“指针”。
从法律上讲,没办法。指向成员的指针的内部结构是实现定义的。
在大多数系统上做这样的事情是违法的,但它是 UB: