2

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

#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
}

Live on Coliru

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

我的问题:

  1. 代码是否完全合法,即通过 a “访问”成员是否合法nullptr,然后获取其地址?如果是这样,那么似乎&(((type*)nullptr)->member)计算成员相对于0的地址,真的是这样吗?(似乎是这样,在最后 3 行中,我得到了相对于 的地址的偏移量s)。
  2. 如果我(void*)从宏定义中删除最终转换为,我会得到一个段错误。为什么?不应该&(((type*)nullptr)->member)是 type 的指针type*,或者这里的类型是否被抹掉了?
4

1 回答 1

6
  1. 代码完全合法吗?

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

您无法实现offsetof宏。不以任何符合标准的方式。

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

尝试打印可能是段错误my_offsetof(S, x)(因为x是 achar并且该表达式导致char*),因为std::ostream'soperator<<将尝试打印char*为 C 样式的 string

于 2016-01-27T03:51:21.697 回答