这会避免UB吗?

Eli*_*gem 5 c undefined-behavior language-lawyer

这个问题更像是一个学术问题,因为没有正当理由再写自己的offsetof宏了.不过,我已经在这里和那里看到了这个本土实现的弹出窗口:

#define offsetof(s, m) ((size_t) &(((s *)0)->m))
Run Code Online (Sandbox Code Playgroud)

从技术上讲,这是取消引用NULL指针(AFAIKT):

C11(ISO/IEC 9899:201x)§6.3.2.3指针第3节

具有该值的整数常量表达式0或此类表达式转换为类型 void *称为空指针常量

所以上面的实现是根据我如何阅读标准,与写作相同:

#define offsetof(s, m) ((size_t) &(((s *)NULL)->m))
Run Code Online (Sandbox Code Playgroud)

它让我怀疑的是,通过改变一个微小的细节,下面的定义offsetof是完全合法的,可靠的:

#define offsetof(s, m) (((size_t)&(((s *) 1)->m)) - 1)
Run Code Online (Sandbox Code Playgroud)

看起来,而不是0,1用作指针,我在结尾处减去1,结果应该是相同的.我不再使用NULL指针了.据我所知,结果是一样的.

所以基本上:有没有理由为什么使用1而不是0在这个offsetof定义中可能不起作用?在某些情况下它仍会导致UB,如果是这样的话:何时以及如何?基本上,我在这里问的是:我在这里错过了什么吗?

oua*_*uah 3

这两个定义都是未定义的行为:在第一个定义中,空指针被取消引用,而在第二个定义中,您取消引用无效指针(该指针不指向有效对象)。在 C 中不可能编写offsetof宏的可移植版本。

缺陷报告#44说:

“特别是,这就是 offsetof 宏存在的原因:否则没有可移植的方法来计算此类平移时间常数。”

(DR#44 适用于 C89,但 C99 和 C11 中的语言没有发生任何改变,从而允许可移植的实现。)