如何比较C指针?

jiy*_*uru 25 c pointers

最近,我写了一些代码来比较像这样的指针:

if(p1+len < p2)
Run Code Online (Sandbox Code Playgroud)

但是,有些工作人员说我应该这样写:

if(p2-p1 > len)
Run Code Online (Sandbox Code Playgroud)

为了安全起见.这里,p1p2char *指针,len是整数.我对此一无所知.是吗?

EDIT1:当然,p1p2在乞讨时指向同一个内存对象.

EDIT2:就在一分钟之前,我在我的代码中找到了这个问题的bogo(大约3K行),因为len它太大了,p1+len不能存储在4个字节的指针中,所以p1 + len <p2真的.但它不应该事实上,所以我认为我们应该在某些情况下比较像这样的指针:

if(p2 < p1 || (uint32_t)p2-p1 > (uint32_t)len)
Run Code Online (Sandbox Code Playgroud)

rua*_*akh 25

通常,只有指针指向同一个内存对象的部分(或者超过对象末尾的一个位置)时,才能安全地比较指针.何时p1,p1 + len以及p2所有符合此规则,您的两个if测试都是等效的,所以您不必担心.另一方面,如果只知道p1并且p2已知符合此规则,并且p1 + len可能远远超过最终,那么只有if(p2-p1 > len)安全.(但我无法想象你的情况就是这样.我假设p1指向一些内存块的开头,p1 + len指向它结束后的位置,对吗?)

他们可能一直在考虑的是整数运算:如果它可能i1 + i2会溢出,但你知道它i3 - i1不会,那么i1 + i2 < i3可以环绕(如果它们是无符号整数)或触发未定义的行为(如果它们是有符号整数)或两者(如果您的系统恰好执行有符号整数溢出的环绕),i3 - i1 > i2而不会有这个问题.


编辑添加:在评论中,你写" len是一个来自buff的值,所以它可能是任何东西".在这种情况下,它们是非常正确的,并且p2 - p1 > len更安全,因为p1 + len可能无效.


Die*_*Epp 12

"未定义的行为"适用于此处.你不能比较两个指针,除非它们都指向同一个对象或指向该对象结束后的第一个元素.这是一个例子:

void func(int len)
{
    char array[10];
    char *p = &array[0], *q = &array[10];
    if (p + len <= q)
        puts("OK");
}
Run Code Online (Sandbox Code Playgroud)

你可能会想到这样的功能:

// if (p + len <= q)
// if (array + 0 + len <= array + 10)
// if (0 + len <= 10)
// if (len <= 10)
void func(int len)
{
    if (len <= 10)
        puts("OK");
}
Run Code Online (Sandbox Code Playgroud)

然而,编译器知道ptr <= q是为所有真正有效的价值ptr,所以它可能优化功能如下:

void func(int len)
{
    puts("OK");
}
Run Code Online (Sandbox Code Playgroud)

快多了!但不是你想要的.

是的,有野外存在的编译器可以做到这一点.

结论

这是唯一安全的版本:减去指针并比较结果,不要比较指针.

if (p - q <= 10)
Run Code Online (Sandbox Code Playgroud)


Jon*_*ler 8

从技术上讲,p1并且p2必须是指针到同一阵列.如果它们不在同一个数组中,则行为未定义.

对于加法版本,类型len可以是任何整数类型.

对于差异版本,减法的结果是ptrdiff_t,但任何整数类型都将被适当地转换.

在这些约束中,您可以以任何方式编写代码; 两者都不正确.在某种程度上,这取决于你正在解决的问题.如果问题是"数组的这两个元素是多于len元素分开",则减法是合适的.如果问题是" p2p1[len](又名p1 + len)相同的元素",则添加是合适的.

实际上,在许多具有统一地址空间的机器上,你可以减少指向不同数组的指针,但你可能会得到一些有趣的效果.例如,如果指针是某些结构类型的指针,而不是同一数组的部分,那么被视为字节地址的指针之间的差异可能不是结构大小的倍数.这可能会导致特殊问题.如果他们指向相同的数组,就不会有这样的问题 - 这就是限制到位的原因.