假设相同类型的两个指针指向同一个数组(或同一个对象),这样两个指针的减法和比较都是有效的...有任何情况下
if(ptr1 - ptr2 > 0)
的行为与
不同if(ptr1 > ptr2)
或者他们在任何时候都是等同的?
答案 0 :(得分:29)
是的,有这样一种情况,两者不的行为相同。
指针差异是签名 [expr.add]:
当减去指向同一数组对象元素的两个指针时,结果就是差异 两个数组元素的下标。结果的类型是实现定义的签名积分 类型;此类型应与
中定义为<cstddef>
标题std::ptrdiff_t
的类型相同
但有两点需要注意:
作为 对于任何其他算术溢出,如果结果不适合所提供的空间,则行为未定义。
除非两个指针都指向同一个数组对象的元素,否则 在数组对象的最后一个元素之后,行为未定义。
在比较方面,我们有[expr.rel]:
- 如果两个指针指向同一个数组的不同元素,或指向其子对象,则指针指向 具有较高下标的元素比较大 - 如果一个指针指向数组的元素或指向其子对象,并指向另一个指针 一个超过数组的最后一个元素,后一个指针比较大 - 如果两个指针指向同一对象的不同非静态数据成员,或指向此类的子对象 成员,递归地,指向后面声明的成员的指针比较大,提供了两个 成员具有相同的访问控制(第11条),并且他们的班级不是工会。
那里的最后一个要点让我们有所不同。考虑:
struct A {
int x, y;
}
A a;
int *px = &a.x, *py = &a.y
px > py
已定义,但px - py > 0
未定义。
当然还有整数溢出情况,如果你有一个庞大的数组:
array[0] > array[PTRDIFF_MAX + 10] // defined
array[0] - array[PTRDIFF_MAX + 10] > 0 // undefined
在这两种情况之外,如果两个指针指向同一个数组(或一个接一个的结尾),则这两个表达式是等价的。如果两个指针指向不同的数组,则两者都是未定义的。
答案 1 :(得分:3)
像if(ptr1 - ptr2 > 0)
这样的构造可能很危险。
最近,我遇到了一个问题,我有两个指向T
的指针:
T* p1;
T* p2;
和
sizeof(T) = 16
现在,有一个错误:p1
和p2
之间的差异小于16.所以p1 - p2
给出了0,这导致了很多错误!
尝试this sample。
最好的解决方案是使用:
if(ptr1 > ptr2)
或:
ptrdiff_t diff = (ptrdiff_t)p2 - (ptrdiff_t)p1;
if(diff > 0)
{
}
所以,基本上,这两个结构可能相同或不同(取决于差异的符号),但有时它们可能不会以相同的方式工作。
指针算术可能非常容易出错。
答案 2 :(得分:0)
在32位系统上,您可能能够分配超过2 GB的数组,并且有两个指向数组开头和结尾的指针,它们的间隔超过2 GB。
在这种情况下,如果ptrdiff_t是带符号的32位整数,则(ptr1> ptr2)将产生true,而(ptr1-ptr2> 0)将是未定义的行为。
(现在由于人们很少这样做,因为编译器错误,ptr1&gt; ptr2可能会给出错误的结果。如果你有两个int *超过2GB,ptr1 - ptr2将被定义为行为,因为正确的结果符合32位有符号数,但如果编译器错误,我也不会感到惊讶。)
答案 3 :(得分:-3)
这取决于你如何在ptr1和ptr2之间进行减法。如果它已经签名,那么它应该可以正常工作,否则如果它是未签名的,结果可能会有所不同。例如:
if (ptr1 > ptr2)
会失败和减法:
ptr1 - ptr2
是无符号的,减法的结果将为正,因此:
if (ptr1 - ptr2 > 0)
将是真的。
我建议使用ptr1&gt; ptr2因为它不容易出错和陷阱。