空指针减法的后果

Consequences of null pointer subtraction

从技术上讲,。 Clang 13 为其发出警告。

然而这个构造无论如何都会被使用,通常用来确定指针的对齐方式。例如,qsort 的 BSD 派生实现使用它。见 here (OpenBSD) and an :

从 OpenBSD 中减去空指针的代码示例片段。请参阅上面的 link 以获得完整的上下文。

#define TYPE_ALIGNED(TYPE, a, es)           \
    (((char *)a - (char *)0) % sizeof(TYPE) == 0 && es % sizeof(TYPE) == 0)

问题:使用典型的现代编译器在典型的现代平台(64 位或 32 位)上使用此类代码是否安全?许多著名的生产代码似乎已经使用这种结构多年。


我注意到像这样的代码已被删除 from FreeBSD's qsort (see revision 334928), because GCC miscompiled some of it. However, I do not understand all the details in the discussion of the issue, and I cannot tell if the problem was a direct consequence of the null pointer subtraction. However, their proposed fix 基本上消除了空指针减法。我将不胜感激关于该主题的一些说明。

编写 C 标准时,许多硬件平台以这样一种方式执行指针运算:将零添加到空指针将产生一个没有副作用的空指针,并且从另一个空指针中减去一个将产生零无副作用。这些行为通常很有用,因为在执行涉及 N 字节存储块(其中 N 可能为零)的任务时,它们可以消除对极端情况代码的需求。

尽管许多平台可以支持上述极端情况而无需生成任何额外的机器代码,但很难说所有平台都能够这样做(我不知道有任何特定平台不能' t,但如果存在这样的平台,也不会感到惊讶)。因此,标准处理此类情况的方式与处理其他情况的方式相同,在其他情况下,几乎所有实现都将以相同的有用方式处理构造,但所有人都这样做可能不切实际:将操作归类为“未定义行为”,但允许实现以作为“一致语言扩展”的一种形式,以与底层执行环境一致的方式对其进行处理。

毫无疑问,应该如何在普通平台上处理此类结构。唯一的疑问是,其目标平台需要额外机器代码来产生常见语义的实现是否应该生成这样的额外机器代码,并且将此类构造分类为 UB 将允许使用此类平台的人员做出此类决定,因此比委员会更适合权衡支持这种司空见惯的行为的成本和收益。