【发布时间】:2015-04-22 08:07:43
【问题描述】:
这个问题更像是一个学术问题,因为没有正当理由编写自己的 offsetof 宏了。尽管如此,我还是经常看到这个本土实现的弹出窗口:
#define offsetof(s, m) ((size_t) &(((s *)0)->m))
从技术上讲,这就是取消引用 NULL 指针 (AFAIKT):
C11(ISO/IEC 9899:201x) §6.3.2.3 指针第 3 节
值为
0的整型常量表达式,或转换为void *类型的表达式称为空指针常量
所以上面的实现是,按照我是怎么看标准的,和写的一样:
#define offsetof(s, m) ((size_t) &(((s *)NULL)->m))
这确实让我想知道,通过改变一个微小的细节,offsetof 的以下定义将是完全合法的,并且可靠:
#define offsetof(s, m) (((size_t)&(((s *) 1)->m)) - 1)
看来,不是用0,而是用1作为指针,最后减1,结果应该是一样的。我不再使用 NULL 指针。据我所知the results are the same。
所以基本上:有什么理由为什么在这个offsetof 定义中使用1 而不是0 可能不起作用?在某些情况下它仍然会导致 UB,如果是:何时以及如何?基本上,我在这里要问的是:我在这里遗漏了什么吗?
【问题讨论】:
-
它不仅是自产的,它在每个标准库中,而且在任何地方都以相同的方式实现。至于您使用
1而不是0的变体,请考虑并非所有平台都可以同样好地处理未对齐访问(有些根本不是)。无论如何,这并不重要,因为编译器无论如何都可以在编译时对其进行评估。 -
@JoachimPileborg:其中,我不完全确定,例如 gcc 依赖于其内部的
__builtin_offsetof。我还没有看到任何无法处理第一个offsetof实现的编译器,但这一点:((s *)NULL)->m从学术角度来看是不正确的,而((s *) 1)->m不是(我认为)跨度>
标签: c language-lawyer undefined-behavior