我一直想知道:ptrdiff_t
是不是应该能够按照定义保存任何两个指针的差异?当两个指针太远时怎么会失败呢? (我没有指出任何特定语言......我指的是所有具有此类型的语言。)
(例如,当你有32位指针时,用地址1
从字节指针中减去地址为0xFFFFFFFF
的指针,它会溢出符号位...)
答案 0 :(得分:28)
不,不是。
$ 5.7 [expr.add] (来自n3225 - C ++ 0x FCD)
当减去指向同一数组对象的元素的两个指针时,结果是两个数组元素的下标的差异。结果的类型是实现定义的有符号整数类型;此类型应与std::ptrdiff_t
标题(18.2)中定义为<cstddef>
的类型相同。与任何其他算术溢出一样,如果结果不适合所提供的空间,则行为未定义。 换句话说,如果表达式P
和Q
分别指向数组对象的i
- 和j
- 元素,则表达式{{1如果值适合类型为(P)-(Q)
的对象,则值为i − j
。此外,如果表达式std::ptrdiff_t
指向数组对象的元素或指向数组对象的最后一个元素,并且表达式P
指向同一数组对象的最后一个元素,表达式Q
与((Q)+1)-(P)
和((Q)-(P))+1
具有相同的值,如果表达式-((P)-((Q)+1))
指向数组对象的最后一个元素之后,则表达式为零,即使表达式P
不指向数组对象的元素。除非两个指针指向同一个数组对象的元素,或者指向数组对象的最后一个元素,否则行为是未定义的。
请注意段落中(Q)+1
出现的次数。另请注意,如果指针指向同一对象,则只能减去指针。
答案 1 :(得分:8)
不,因为“任何两个指针”之间没有区别。您只能减去指向同一数组元素的指针(或指向数组末尾的位置的指针)。
答案 2 :(得分:2)
要添加更明确的标准报价,ISO 9899:1999 §J.2/1
说明:
在以下情况下,行为未定义:
[...]
- 减去两个指针的结果在类型的对象中无法表示 ptrdiff_t(6.5.6)。
答案 3 :(得分:1)
如果编译器定义了溢出语义,那么ptrdiff_t
与指针类型的大小完全相同,这样任何差异仍然可以表示。无法保证负ptrdiff_t意味着第二个指针位于内存中比第一个更低的地址,或者ptrdiff_t完全被签名。
答案 4 :(得分:-2)
对于固定大小的整数运算,上/下流在数学上是明确定义的:
(1 - 0xFFFFFFFF) % (1<<32) =
(1 + -0xFFFFFFFF) % (1<<32) =
1 + (-0xFFFFFFFF % (1<<32)) = 2
这 是正确的结果!
具体地说,上溢/下溢后的结果是正确整数的别名。实际上,每个不可表示的整数都有一个可表示的整数别名(无法区分) - 在固定大小的整数中计数到无穷大,你会重复自己,像模拟时钟表盘那样圆形和圆形。
N位整数表示模2 ^ N的任何实数。在C中,模2 ^ N被写为%(1 <&lt; 32)。
我相信C保证上溢/下溢的数学正确性,但仅适用于无符号整数。假定签名在/溢出下永远不会发生(为了优化)。
实际上,有符号整数是二进制补码,这在加法或减法方面没有区别,因此对于有符号整数也保证正确的欠/溢出行为(尽管不是C)。