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

时间:2016-01-27 03:38:44

标签: c++ offsetof

我正在查看来自<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
}

Live on Coliru

我所做的唯一修改就是我使用最终广告投放到void*而不是size_t,因为我想将地址显示为指针。

我的问题:

  1. 代码是否完全合法,即访问&#34;是否合法?通过nullptr成员,然后取其地址?如果是这种情况,那么似乎&(((type*)nullptr)->member)计算成员相对于0的地址,这是否确实如此? (看起来如此,就像在最后3行中我得到的偏移相对于s的地址)。
  2. 如果我从宏定义中删除最终的强制转换为(void*),我会得到一个段错误。为什么?不应该&(((type*)nullptr)->member)type*类型的指针,还是某种方式在此删除?

1 个答案:

答案 0 :(得分:5)

  
      
  1. 代码完全合法吗?
  2.   

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

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

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

尝试打印my_offsetof(S, x)可能是一个段错误(因为xchar而该表达式会产生char*),因为std::ostream's operator<< will try to print char* as a C-style string。< / p>