1

offsetof定义如下stddef.h

#define offsetof(type, member) ((size_t)&((type *)0)->member)

由于取消引用 NULL 指针,这是否会调用未定义的行为?如果不是,为什么?

4

2 回答 2

5

在普通 C 代码中,((size_t)&((type *)0)->member)C 标准未指定 的行为:

  • 首先,根据 C 2018 6.5.2.3 4,about->指定指向的结构((type *)0)->member成员的左值。但不指向结构,因此没有成员 this 可以是左值。member(type *)0((type *)0)
  • 假设它确实为某个假设结构提供了左值,则无法保证获取其地址并将其转换为size_t产生成员的偏移量,因为我们不知道这会(type *)0产生一个在实现寻址中实际上用零表示的地址方案并且因为将指针转换为 C 2018 6.3.2.3 6 指定的整数只告诉我们结果是实现定义的,而不是它以任何其他有意义的形式产生地址。

如果此代码在标准头文件中,例如<stddef.h>,它在 C 实现而不是 C 标准的控制下,因此关于它是否根据 C 标准未定义的问题不适用。C 标准仅说明标准头文件在包含时的行为方式——实现可以使用它选择的任何方式来实现所需的效果,无论是简单地定义 C 标准未完全定义的源代码的行为,还是将源代码放入在标题中使用完全不同的语言。(事实上​​,文件 stddef.h 可能完全为空或根本不存在,编译器可以在看到时提供其所需的声明,#include <stddef.h>而无需从磁盘读取任何实际文件。)

于 2019-08-03T21:37:27.650 回答
-3

撇开它可能不是正确实现的所有其他原因offsetof

#define offsetof(type, member) ((size_t)&((type *)0)->member)

即使作为实现的一部分也不合适,因为 in 中的所有内容都stddef.h必须在 C 和 C++ 中正常工作,并且在 C++ 中,上述构造在重载的情况下肯定会出现异常operator->。这就是为什么 GCCstddef.h转而使用__builtin_offsetof十五年前称为的特殊内在函数的原因。

是的,我是说如果你在某些地方看到这个stddef.h,那stddef.h是错误的。

于 2019-08-03T22:16:20.827 回答