ptrdiff_t 可以表示指向同一个数组对象的元素的指针的所有减法吗?

Can ptrdiff_t represent all subtractions of pointers to elements of the same array object?

对于指向同一数组对象 the note in [expr.add#5] 的元素的指针 ij 的减法读取:

[ Note: If the value i−j is not in the range of representable values of type std​::​ptrdiff_­t, the behavior is undefined. — end note ]

但是给定 [support.types.layout#2],其中指出(强调 我的):

  1. The type ptrdiff_­t is an implementation-defined signed integer type that can hold the difference of two subscripts in an array object, as described in [expr.add].

有没有可能i-j的结果不在ptrdiff_t的可表示值范围内?

PS: 如果我的问题是由于我对英语的理解不佳引起的,我深表歉意。

编辑: 相关:

Is it even possible for the result of i-j not to be in the range of representable values of ptrdiff_t?

是的,但不太可能。

事实上,[support.types.layout]/2除了在[expr.add]中定义了有关指针减法和ptrdiff_t的正确规则外,并没有说太多。那么让我们看看这个部分。

[expr.add]/5

When two pointers to elements of the same array object are subtracted, the type of the result is an implementation-defined signed integral type; this type shall be the same type that is defined as std​::​ptrdiff_­t in the <cstddef> header.

首先注意,不考虑ij是不同数组下标索引的情况。这允许将 i-j 视为 P-Q,其中 P 是指向下标 i 处的数组元素的指针,而 Q 是指向数组元素的指针相同 数组的元素位于下标 j。实际上,将指向不同数组元素的两个指针相减是 未定义的行为:

[expr.add]/5

If the expressions P and Q point to, respectively, elements x[i] and x[j] of the same array object x, the expression P - Q has the value i−j ; otherwise, the behavior is undefined.

综上所述,根据前面定义的符号,i-jP-Q被定义为具有相同的值,后者是std::ptrdiff_t. But nothing is said about the possibility for this type to hold such a value. This question can, however, be answered with the help of std::numeric_limits类型;特别是,可以检测数组 some_array 是否 对于 std::ptrdiff_t 来说太大 以容纳所有索引差异:

static_assert(std::numeric_limits<std::ptrdiff_t>::max() > sizeof(some_array)/sizeof(some_array[0]),
    "some_array is too big, subtracting its first and one-past-the-end element indexes "
    "or pointers would lead to undefined behavior as per [expr.add]/5."
);

现在,在通常的目标上,这通常不会发生 sizeof(std::ptrdiff_t) == sizeof(void*);这意味着数组需要非常大才能使 ptrdiff_t 溢出。但不能保证。

我认为这是措辞的错误。

[expr.add]中的规则继承自 C 标准中指针减法的相同规则。在 C 标准中,ptrdiff_t 不需要保存数组对象中两个下标的任何差异。

[support.types.layout]中的规则来自Core Language Issue 1122。它增加了std::size_tstd::ptrdiff_t的直接定义,这是为了解决循环定义的问题。我看不出有任何理由(至少在任何官方文档中都没有提到)使 std::ptrdiff_t 保留数组对象中两个下标的任何差异。我猜它只是使用了一个不正确的定义来解决循环定义问题。

作为另一个证据,[diff.library] 没有提到 C++ 中的 std::ptrdiff_t 和 C 中的 ptrdiff_t 之间的任何区别。因为在 C 中 ptrdiff_t 没有这样的约束,在C++ std::ptrdiff_t 也不应该有这样的约束。