假设同一类型的两个指针指向同一数组(或同一对象),这样两个指针的相减和比较都有效。。。有的情况吗
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
现在,出现了一个错误:p1
和p2
之间的差异小于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,因为它不太容易出现错误和陷阱。