首页 > 解决方案 > 减去与同一数组未定义行为无关的两个指针的基本原理是什么?

问题描述

根据 C++ 草案expr.add当您减去相同类型但不属于同一数组的指针时,行为未定义(重点是我的):

当两个指针表达式 P 和 Q 相减时,结果的类型是实现定义的有符号整数类型;此类型应与在标头 ([support.types]) 中定义为 std::ptrdiff_t 的类型相同。

  • 如果 P 和 Q 都计算为空指针值,则结果为 0。 (5.2)

  • 否则,如果 P 和 Q 分别指向同一数组对象 x 的元素 x[i] 和 x[j],则表达式 P - Q 的值为 i-j。

  • 否则,行为未定义。 [注意:如果值 i−j 不在 std::ptrdiff_t 类型的可表示值范围内,则行为未定义。——尾注]

使这种行为未定义而不是例如实现定义的基本原理是什么?

标签: c++language-lawyerpointer-arithmetic

解决方案


从学术上讲:指针不是数字。它们是指针。

确实,系统上的指针被实现为某种抽象类型的内存(可能是虚拟的,每个进程的内存空间)中位置的类似地址表示的数字表示。

但是 C++ 并不关心这一点。C++ 希望您将指针视为指向特定对象的便利贴、书签。数字地址值只是一个副作用。唯一对指针有意义的算术是通过对象数组向前和向后。没有其他任何东西具有哲学意义。

这可能看起来非常神秘和无用,但它实际上是经过深思熟虑和有用的。C++ 不希望将实现限制为赋予它无法控制的实用、低级计算机属性更多的意义。而且,由于它没有理由这样做(你为什么要这样做?)它只是说结果是未定义的。

在实践中,您可能会发现您的减法有效。然而,编译器极其复杂,并且充分利用标准的规则来生成尽可能快的代码;当您违反规则时,这可能并且经常会导致您的程序看起来做一些奇怪的事情。当编译器假定原始值和结果都引用同一个数组时,如果您的指针算术运算被破坏,请不要太惊讶——您违反了这个假设。


推荐阅读