通过强制转换 nullptr 获取成员变量的偏移量



我正在查看<cstddef>的宏offsetof,并看到可能的实现是通过

#define my_offsetof(type, member) ((void*) &(((type*)nullptr)->member))

我试过了,确实它按预期工作

#include <iostream>
#define my_offsetof(type, member) ((void*) &(((type*)nullptr)->member))
struct S
{
    char x;
    short y;
    int z;
};
int main()
{
    std::cout << my_offsetof(S, x) << 'n';
    std::cout << my_offsetof(S, y) << 'n';
    std::cout << my_offsetof(S, z) << 'n';
    S s;
    std::cout << (void*) &((&s)->x) << 'n'; // no more relative offsets
    std::cout << (void*) &((&s)->y) << 'n'; // no more relative offsets
    std::cout << (void*) &((&s)->z) << 'n'; // no more relative offsets
}

住在科里鲁

所做的唯一修改是我使用最终强制转换来void*而不是size_t,因为我想将地址显示为指针。

我的问题:

  1. 代码是否完全合法,即通过nullptr"访问"成员,然后获取其地址是否合法?如果是这样的话,那么似乎&(((type*)nullptr)->member)计算成员相对于 0 的地址,事实确实如此吗?(似乎是这样,因为在最后 3 行中,我得到了相对于 s 地址的偏移量)。
  2. 如果我从宏定义中删除要(void*)的最终转换,则会出现段错误。为什么?&(((type*)nullptr)->member)不应该是类型 type* 的指针,还是该类型在此处以某种方式被删除?
  1. 代码完全合法吗?

不。这是未定义的行为。编译器可以选择以这种方式实现offsetof,但那是因为它实现:它可以选择如何实现自己的功能。另一方面,你没有得到这样的"奢侈品"。

您无法实现offsetof宏。不符合任何标准。

  1. 如果我从宏定义中删除最终转换为 (void*),我会得到一个段错误。为什么?&((type*)nullptr)->member) 不应该是类型为 * 的指针,还是此处以某种方式删除了该类型?

这可能是尝试打印my_offsetof(S, x)的段错误(因为x是一个char并且该表达式会导致char*),因为std::ostreamoperator<<将尝试将char*打印为C样式字符串。

相关内容

  • 没有找到相关文章

最新更新