我正在查看来自<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
,因为我想将地址显示为指针。
我的问题:
nullptr
成员,然后取其地址?如果是这种情况,那么似乎&(((type*)nullptr)->member)
计算成员相对于0的地址,这是否确实如此? (看起来如此,就像在最后3行中我得到的偏移相对于s
的地址)。 (void*)
,我会得到一个段错误。为什么?不应该&(((type*)nullptr)->member)
是type*
类型的指针,还是某种方式在此删除?答案 0 :(得分:5)
- 代码完全合法吗?
醇>
没有。 It's undefined behavior。编译器可以选择以这种方式实现offsetof
,但这是因为它 实现:它可以选择如何实现自己的功能。另一方面,你不会得到这样的“奢侈品”。
您无法实现offsetof
宏。不符合任何标准的方式。
- 如果我从宏定义中删除最终的强制转换为(void *),我会得到一个段错误。为什么?不应该&(;(type *)nullptr) - &gt; member)是一个类型为*的指针,还是这里以某种方式删除的类型?
醇>
尝试打印my_offsetof(S, x)
可能是一个段错误(因为x
是char
而该表达式会产生char*
),因为std::ostream
's operator<<
will try to print char*
as a C-style string。< / p>