是否有任何情况"ptr1 - ptr2 > 0"会与"ptr1 > ptr2"不同?



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

if(ptr1 - ptr2 > 0)

将与表现不同

if(ptr1 > ptr2)

或者它们在任何时候都是等价的?

是的,在这种情况下,两者的行为将不相同。

指针差有符号[expr.add]:

当减去指向同一数组对象的元素的两个指针时,结果是两个数组元素的下标。结果的类型是由定义的实现,签名积分类型该类型应与<cstddef>标头中定义的std::ptrdiff_t类型相同

但有两个注意事项:

As对于任何其他算术溢出,如果结果不符合所提供的空间,则行为是未定义的。

除非两个指针都指向同一数组对象的元素,或者超过数组对象的最后一个元素,则行为未定义。

在比较方面,我们有[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

在这两种情况之外,如果两个指针指向同一个数组(或超过末尾的一个),那么这两个表达式是等价的。如果两个指针指向不同的数组,那么这两个指针都是未定义的。

if(ptr1 - ptr2 > 0)这样的构造可能很危险。

最近,我遇到了一个问题,我有两个指向类型T:的指针

T* p1;
T* p2;

sizeof(T) = 16

现在,出现了一个错误:p1p2之间的差异小于16。所以p1 - p2给出了0,这导致了很多错误!

试试这个例子。

最好的解决方案是使用其中一种:

if(ptr1 > ptr2)

或:

ptrdiff_t diff = (ptrdiff_t)p2 - (ptrdiff_t)p1;
if(diff > 0)
{
}

所以,基本上,这两个结构可能等价,也可能不等价(取决于差异的符号),但有时它们可能不以相同的方式工作。

指针运算可能非常容易出错。

在32位系统上,您可能能够分配一个超过2GB的数组,并且有两个指向数组开始和结束的指针,它们之间的距离超过2GB。

在这种情况下,(ptr1>ptr2)将产生true的结果,而如果ptrdiff_t是有符号的32位整数,则(ptr1-ptr2>0)将是未定义的行为。

(现在,由于人们很少这样做,ptr1>ptr2很有可能因为编译器错误而给出错误的结果。如果你有两个相距超过2GB的int*,ptr1-ptr2将被定义为行为,因为正确的结果适合一个32位有符号的数字,但如果编译器弄错了,我不会感到惊讶)。

这取决于如何在ptr1和ptr2之间进行减法。如果它是有符号的,那么它应该可以正常工作,否则如果它是无符号的,结果可能会不同。例如:

if (ptr1 > ptr2)

将失败并进行减法运算:

ptr1 - ptr2

是无符号的,减法的结果将是正的,因此:

if (ptr1 - ptr2 > 0)

将是真的。

我建议使用ptr1>ptr2,因为它不太容易出现错误和陷阱。

最新更新