2

我遇到了以下c ++代码:

 #define OFFSETOF_MEMBER(t, f) \
  (reinterpret_cast<uintptr_t>(&reinterpret_cast<t*>(16)->f) - static_cast<uintptr_t>(16u)) // NOLINT

其中 t 是类型,f 是字段名称。我想知道为什么我们可以将整数 16 作为 reinterpret_cast 的参数。

4

3 回答 3

1

16 是我们分配给指针的地址,它可以让我们计算指定成员的偏移量。指针的地址只是一个数字,因此我们可以滥用这一事实来获取有关我们的结构/类的信息。

假设我们有一个结构:

struct point { 
    //Assuming 32-bit integer sizes. 
    //For 64-bit integersizes, 0x0, 0x8, 0x10 for the integer offsets
    int x; //Offset 0x0
    int y; //Offset 0x4
    int z; //Offset 0x8
}; static_assert(sizeof(point) == 12 /* or 0xC in hex */);

我们使用宏:

OFFSETOF_MEMBER(point, y);

展开宏,我们得到:

(reinterpret_cast<uintptr_t>(&reinterpret_cast<point*>(16)->y) - static_cast<uintptr_t>(16u)

另一种表达方式reinterpret_cast<point*>(16)->y可能是这样的:point * myPt = 16u;我们知道 16 不是有效地址,但编译器没有,只要我们不尝试读取我们指向的地址,我们就可以.

接下来,我们可以将所有内容简化&reinterpret_cast<point*>(16)->y为:&myPt->y。我们从上面知道 y 是@offset 0x4,并且由于 myPt 是 16:16 + 0x4 = 20

然后我们有reinterpret_cast<uintptr_t>(20u) - static_cast<uintptr_t(16u)or 20 - 16,它给出了 y 的偏移量,即 0x4。

于 2018-07-18T07:19:22.047 回答
0

整数 16 只是一个内存地址。表达式reinterpret_cast<t*>(16)只是意味着“将地址 16 处的对象解释为类型t”,但您知道该地址处没有这样的t对象。理论上,16可以替换为任何 4x(32 位)或 8x(64 位)整数。如果选择0,宏可以简化为:

#define OFFSETOF_MEMBER(t, f) \
  (reinterpret_cast<uintptr_t>(&reinterpret_cast<t*>(0)->f))

有关更多信息,请参见offsetof

于 2018-07-18T07:01:37.457 回答
0

参考

3) 任何整数或枚举类型的值都可以转换为指针类型。[...]

因此,reinterpret_cast<>部分设计就是为了做到这一点。

于 2018-07-18T06:50:09.343 回答