【发布时间】:2016-01-27 03:38:44
【问题描述】:
我正在查看来自<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*类型的指针,还是该类型在这里被抹掉了?
【问题讨论】:
-
取消引用空指针是 UB,即使它只是获取它的地址。
-
@JonathanPotter 这就是我的想法,虽然不确定。所以cppreference“可能的实现”被打破了。然后你将如何实现这个宏?
-
@vsoftco:并非 C++ 标准中指定的所有内容都可以由用户重新实现。某些事物,例如
offsetof或std::complex(例如),无法以符合标准的方式实现。 -
@Cornstalks 我明白了...
std::complex有什么问题?不就是一个struct有 2 个成员和一些成员函数吗? -
@vsoftco:保证没有任何填充,并且可以转换为
float[2](或double[2])数组。 Unfortunately, there is no mechanism in the C++ standard that lets users provide that level of guarantee with their own classes.