“ptr1 - ptr2> 0”与“ptr1> ptr2”有什么不同?

时间:2015-04-20 11:21:19

标签: c++ pointers

假设相同类型的两个指针指向同一个数组(或同一个对象),这样两个指针的减法和比较都是有效的...有任何情况下

if(ptr1 - ptr2 > 0)

的行为与

不同
if(ptr1 > ptr2)

或者他们在任何时候都是等同的?

4 个答案:

答案 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

现在,有一个错误:p1p2之间的差异小于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因为它不容易出错和陷阱。