ptrdiff_t 可以表示指向同一个数组对象的元素的指针的所有减法吗?
Can ptrdiff_t represent all subtractions of pointers to elements of the same array object?
对于指向同一数组对象 the note in [expr.add#5] 的元素的指针 i
和 j
的减法读取:
[ 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],其中指出(强调 我的):
- 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.
首先注意,不考虑i
和j
是不同数组下标索引的情况。这允许将 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-j
和P-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_t
和std::ptrdiff_t
的直接定义,这是为了解决循环定义的问题。我看不出有任何理由(至少在任何官方文档中都没有提到)使 std::ptrdiff_t
保留数组对象中两个下标的任何差异。我猜它只是使用了一个不正确的定义来解决循环定义问题。
作为另一个证据,[diff.library] 没有提到 C++ 中的 std::ptrdiff_t
和 C 中的 ptrdiff_t
之间的任何区别。因为在 C 中 ptrdiff_t
没有这样的约束,在C++ std::ptrdiff_t
也不应该有这样的约束。
对于指向同一数组对象 the note in [expr.add#5] 的元素的指针 i
和 j
的减法读取:
[ 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],其中指出(强调 我的):
- 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 ofptrdiff_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.
首先注意,不考虑i
和j
是不同数组下标索引的情况。这允许将 i-j
视为 P-Q
,其中 P
是指向下标 i
处的数组元素的指针,而 Q
是指向数组元素的指针相同 数组的元素位于下标 j
。实际上,将指向不同数组元素的两个指针相减是 未定义的行为:
[expr.add]/5
If the expressions
P
andQ
point to, respectively, elementsx[i]
andx[j]
of the same array objectx
, the expressionP - Q
has the valuei−j
; otherwise, the behavior is undefined.
综上所述,根据前面定义的符号,i-j
和P-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_t
和std::ptrdiff_t
的直接定义,这是为了解决循环定义的问题。我看不出有任何理由(至少在任何官方文档中都没有提到)使 std::ptrdiff_t
保留数组对象中两个下标的任何差异。我猜它只是使用了一个不正确的定义来解决循环定义问题。
作为另一个证据,[diff.library] 没有提到 C++ 中的 std::ptrdiff_t
和 C 中的 ptrdiff_t
之间的任何区别。因为在 C 中 ptrdiff_t
没有这样的约束,在C++ std::ptrdiff_t
也不应该有这样的约束。