两个比较相等的指针是否转换为整数比较是否相等?

Som*_*ame 6 c pointers language-lawyer

问题:如果指针比较等于,它们的整数转换值也等于吗?

例如:

void *ptr1 = //...
void *ptr2 = //...
printf("%d", ptr1 == ptr2); //prints 1
Run Code Online (Sandbox Code Playgroud)

这是否意味着(intptr_t) ptr1 == (intptr_t) ptr2也1?

从务实的角度来看应该是正确的。但是考虑标准在7.20.1.4(p1)以下方面指定的内容:

以下类型指定了一个带符号的整数类型,其属性是void可以将任何有效指针都转换为该类型,然后再转换回到的指针void,结果将与原始指针进行比较:

    intptr_t
Run Code Online (Sandbox Code Playgroud)

它与实现可以将相同的指针转换为不同的值(取决于某些奇怪的情况)并不矛盾,这保留了转换回的值产生相同的指针。

因此,我认为不,比较相等的指针的整数转换值不必彼此相等。

Sto*_*ica 7

您的分析是正确的。除了在第6.3.2.3节中允许在整数之间进行转换外,该标准没有提及该转换应如何进行。当然,上有一个“往返”要求intptr_t,但是它不能阻止一个以上的往返,编译器会根据某些约束或要求选择一个或另一个。

因此,确实,C标准不需要(intptr_t) ptr1 == (intptr_t) ptr2保留。

  • @SomeName-是的。 (2认同)

sup*_*cat 6

指针的大小介于两个整数类型(例如,分段模式80386,其中指针为48位)之间的实现可能会处理以下内容:

uintptr_t my_uintptr = (uintptr_t)myptr;
Run Code Online (Sandbox Code Playgroud)

如果以后的转换忽略了这些位的值,则将它们存储myptr到的前48位my_uintptr并保留剩余的任意值myptr = (void*)my_uintptr;。

由于不能保证重复重复转换相同的指针uintptr_t会产生相同的值,因此即使通过不同的方式产生的转换后的指针比较相等,也无法保证。

但是,如果某个实现记录了指针和整数的存储格式,并记录了转换的执行方式,并且如果在没有坚持更强语义保证的情况下无法以与该文档一致的方式进行某种行为,那么该实现应该有望坚持此类保证。我认为标准不是要求实现以与其文档一致的方式作为符合性的条件,但是应该期望高质量实现的行为与所记录的一样,这一观点是不言而喻的,因此本标准不需要要求它。

  • 这是一个绝妙的例子,说明这种假设可能会失败。 (2认同)
  • @BenZotto:我不知道是否有任何使用48位指针的80386编译器支持64位整数类型,或者它们只是没有定义uintptr_t,因为到C99时,添加了64位类型,x86上几乎所有内容使用“平面” 32位模式,对所有内容使用单个段。此外,我认为该模式的质量编译器应该提供一个选项,以明确清除uintptr_t的高位,而不必考虑标准是否要求它,即使它也提供了使这些位不确定的选项。 (2认同)

Kei*_*son 6

在几乎所有的实现中,两个指针均当且仅当它们的表示形式相等时才相等,但该标准不保证这样做。

这一事实ptr1 == ptr2并不意味着ptr1与ptr2具有相同的表示。N1570 6.5.9第6段:

当且仅当两个都是空指针时两个指针比较相等,两个指针都是指向同一对象的指针(包括指向对象和它的开始处的子对象的指针)或函数,都是指向同一数组最后一个元素的指针对象,或者一个是指向一个数组对象末尾的指针,另一个是指向另一个数组对象的起点的指针,该数组对象恰好紧随地址空间中的第一个数组对象。

例如,假设一个指针被表示为一个两部分的实体,其中第一部分标识一个内存段,第二部分标识该段内的字节偏移量。如果两个段可以重叠,则同一内存地址可以有两个不同的指针表示形式。这两个指针将比较相等(并且生成的代码可能必须做一些额外的工作才能实现),但是如果转换为intptr_t仅复制表示形式,则(intptr_t)ptr1 != (intptr_t)ptr2。

(指针到整数的转换也可能使表示形式标准化。)

这可能就是为什么==和!=为指针,以不同的对象是有严格规定的,但关系运算符(<,<=,>,>=)是不确定的。相等运算符必须确定两个指针是否指向相同的位置,但是关系运算符只能比较偏移量而忽略基数部分(假设每个对象都在单个段中)。实际上,几乎所有现代系统都具有一个整体的地址空间,即使标准不要求平等和关系运算符也能始终如一地工作。

  • @JL2210:这是合法的,因为不允许它是不切实际的。给定 `int x; 整数y;int *p0 = &amp;x + 1; int *p1 = &amp;y; if (p0 == p1) ...`,如果内存中`y`恰好紧跟在`x`之后,那么`p0`和p1`将指向相同的内存位置。使“p0 == p1”产生错误结果将需要不合理的额外工作。 (2认同)