【问题标题】:Consequences of null pointer subtraction空指针减法的后果
【发布时间】:2021-12-16 02:39:21
【问题描述】:

技术上,subtracting a null pointer is undefined behaviour in C。 Clang 13 对其发出警告。

然而,这个结构无论如何都会被使用,通常用于确定指针的对齐方式。例如,qsort 的 BSD 派生实现使用它。见here (OpenBSD)explanation of what it's for

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

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

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


我注意到像这样的代码已被删除from FreeBSD's qsort(请参阅修订版334928),因为 GCC 错误编译了其中的一些。但是,我不了解问题的discussion 中的所有细节,并且我无法判断问题是否是空指针减法的直接后果。但是,their proposed fix 基本上消除了空指针减法。我将不胜感激有关该主题的一些澄清。

【问题讨论】:

  • 请提供演示问题的相关代码,而不是提供参考。
  • @VladfromMoscow 有几个相关代码的链接,包括 StackOverflow 的链接。
  • 从描述中不清楚是什么问题。
  • 你写了“这样的代码可以安全使用吗...”什么代码?您的问题中的代码在哪里?
  • 在您讨论该问题的链接中,我没有看到关于减法(char *) 0 的讨论,至少不是直接的。是不是和那里有什么联系?哪个特定文本讨论了减法,您对此有疑问吗?那里的一些文字提到代码违反了别名规则,这不是我描述(char *) a - (char *) 0的方式。

标签: c alignment undefined-behavior null-pointer


【解决方案1】:

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

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

对于在普通平台上应如何处理此类构造,我们从来没有任何疑问。唯一的疑问是,其目标平台需要额外的机器代码来产生普通语义的实现是否应该生成这样的额外机器代码,并且将此类构造分类为 UB 将允许使用此类平台的人做出此类决定,因此比委员会更能权衡支持普通行为的成本和收益。

【讨论】:

  • 让我总结一下,以确认我的理解:在大多数现代平台上,减去一个空指针是没有问题的,例如int *p;p - (int *) 0。正如@EricPostpischil 在 cmets 中指出的那样,我链接的 GCC 讨论中提到的问题并不是空指针减法的直接后果。空指针减法在标准中是“未定义行为”的原因是它在某些过时的平台上无法得到合理的支持。
  • @Szabolcs:这就是 原因 它是 UB。另一方面。 Gratuitously Clever Compiler 的维护者将短语“不可移植或错误”视为“不可移植,因此是错误的”这一事实意味着 gcc 编译器应该与依赖于什么的代码不必要地不兼容。该标准的作者将此类称为“流行扩展”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-04-10
  • 2019-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-14
  • 1970-01-01
相关资源
最近更新 更多