C++ 通过强制转换null ptr获取成员变量的偏移量

C++ 通过强制转换null ptr获取成员变量的偏移量,c++,offsetof,C++,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; s

我正在查看
中的宏,并看到可能的实现是通过

#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*)和((type*)nullptr)->member)的我的偏移量
结构
{
字符x;
短y;
intz;
};
int main()
{
std::cout member)
计算成员相对于0的地址,是否确实如此?(似乎如此,在最后3行中,我得到了相对于
s
地址的偏移量)
  • 如果我从宏定义中删除对
    (void*)
    的最终强制转换,我会得到一个segfault。为什么?
    &((type*)nullptr)->成员)
    不应该是
    type*
    类型的指针,或者该类型在这里被删除了吗
  • 守则完全合法吗
  • 不,编译器可以选择以这种方式实现
    offsetof
    ,但这是因为它就是实现:它可以选择如何实现自己的功能。另一方面,你不会得到这样的“奢侈”

    您无法以任何符合标准的方式实现宏的偏移量

  • 如果我从宏定义中删除对(void*)的最终强制转换,我会得到一个segfault。为什么&((type*)nullptr)->member)不应该是类型为*的指针,或者该类型在这里被删除了吗

  • 这可能是因为试图打印
    my_offset of(s,x)
    (因为
    x
    char
    ,而该表达式会导致
    char*
    ),因为。

    取消对空指针的引用是错误的,即使它只是获取它的地址。@JonathanPotter这是我的想法,尽管我不确定。所以CPP引用“可能的实现”被打破了。你将如何实现这个宏?@ VSOFTCO:不是C++中指定的所有东西都可以由用户重新实现。某些东西,如<代码> Office < <代码>或<代码> STD::,不能以符合标准的方式实现。@cornstales我明白了。
    std::complex
    有什么问题吗?它不只是一个有两个成员和一些成员函数的
    结构吗?@vsoftco:它保证没有任何填充,可以转换为
    浮点[2]
    (或
    双[2]
    )数组..不确定我是否理解“编译器可能会选择以这种方式实现offsetof,但那是因为它是实现。“你的意思是编译器内部有一个定义良好的行为,在这种情况下,根据定义?@vsoftco:我的意思是编译器需要提供一些
    宏的偏移量。但是,如何做到这一点取决于编译器。如果他们选择这样做,他们可以创建
    &((type*)nullptr)->成员)
    宏的
    偏移量定义得很好。但这并不意味着你自己的宏定义得很好。@Cornstales,在你的最后一句话中s/可能/:)谢谢,这也是我从你的回答中理解的。哦,我也看到了
    字符的情况……出于某些原因,我认为类型是
    s*
    ,但类型是是指向该成员的指针,因此每当该成员是
    char
    时,由于调用
    char*
    重载,该指针就会断开+1@vsoftco您所做的可能不会在所有编译器上都起作用。但它可能在GCC 5上起作用。如果它在GCC上起作用,但在MSVC上不起作用,那么MSVC将提供自己的宏,该宏与在MSVC上起作用的宏不同。如果您使用自己的版本,然后您将不知道如何为MSVC更改它,并且您的代码将无法在MSVC上工作。