问题: 如果比较相等的指针的整数转换值也相等吗?
例如:
void *ptr1 = //...
void *ptr2 = //...
printf("%d", ptr1 == ptr2); //prints 1
这是否意味着(intptr_t) ptr1 == (intptr_t) ptr2
也是1
?
从务实的角度来看应该是正确的。但是请考虑标准在7.20.1.4(p1)
中指定的内容:
以下类型用属性指定一个带符号整数类型 任何指向
void
的有效指针都可以转换为这种类型,然后 转换回指向void
的指针,结果将比较相等 指向原始指针:intptr_t
与实现可以将相同的指针转换为不同的值(取决于某些奇怪的情况)并不矛盾,这保留了转换回的值产生相同的指针。
所以,我认为不,比较相等的指针的整数转换值不必彼此相等。
答案 0 :(得分:6)
您的分析是正确的。除了允许在§6.3.2.3处进行整数转换外,该标准没有提及该转换应如何进行。当然,intptr_t
上有一个“往返”要求,但它不能阻止一个以上的行程,而编译器会根据某些约束或要求选择一个或另一个行程。
所以确实,C标准不需要(intptr_t) ptr1 == (intptr_t) ptr2
来保存。
答案 1 :(得分:6)
其中指针大小介于两种整数类型(例如,分段模式80386,其中指针为48位)之间的实现可能会处理以下内容:
uintptr_t my_uintptr = (uintptr_t)myptr;
通过将myptr
存储到my_uintptr
的前48位中,并让其余的位保留任意值,条件是以后的转换myptr = (void*)my_uintptr;
忽略那些位的值。
由于不能保证将相同指针重复转换为uintptr_t
会产生相同的值,因此即使在转换后的指针比较相等的情况下,也无法保证通过不同的方式产生。
但是,如果某个实现记录了指针和整数的存储格式,并记录了转换的执行方式,并且如果在没有坚持更强语义保证的情况下无法以与该文档一致的方式进行行为,那么预计实施将坚持这种保证。我认为标准不是要求实现以与文档一致的方式作为符合性的条件,但是应该期望高质量实现的行为与所记录的一样,这一观点不言而喻,因此本标准不需要要求它。
答案 2 :(得分:6)
在几乎所有的实现中,两个指针均当且仅当它们的表示形式相等时才相等,但标准不对此予以保证。
ptr1 == ptr2
并不意味着ptr1
和ptr2
具有相同的表示。 N1570 6.5.9第6段:
当且仅当两个都是空指针时,两个指针比较相等 是指向同一对象的指针(包括指向对象的指针和 子对象的开头)或函数,两者都是指向一个对象的指针 越过同一数组对象的最后一个元素,或者一个指针指向 一个超过一个数组对象的末尾,另一个是指向该数组的指针。 恰好紧随其后的另一个数组对象的开始 地址空间中的第一个数组对象。
例如,假设一个指针由两部分组成,第一部分标识一个内存段,第二部分标识该段内的字节偏移量。如果两个段可以重叠,则同一内存地址可以有两个不同的指针表示形式。这两个指针的比较是相等的(生成的代码可能需要做一些额外的工作才能实现),但是如果转换为intptr_t
只是复制表示形式,那么(intptr_t)ptr1 != (intptr_t)ptr2
。
(指针到整数的转换也有可能规范化表示形式。)
这种可能性就是为什么==
和!=
可以很好地定义指向不同对象的指针,但是关系运算符(<
,<=
,>
, >=
)未定义。相等运算符必须确定两个指针是否指向相同的位置,但是关系运算符只能比较偏移量而忽略基数部分(假设每个对象都在单个段中)。实际上,几乎所有现代系统都具有整体地址空间,即使标准不要求平等和关系运算符也能始终如一地工作。