我把这个问题从最后一个问题中删除了,因为我认为这是一个单独的问题。所以我在标准中找到了指针转换的段落,关于我的问题的段落是:
6.3.2.3
指针
1 指向 void 的指针可以转换为指向任何 对象类型。 指向任何对象类型的指针都可以转换为 指向 void 并再次返回的指针; 结果应相等 到原始指针。
。
4 将一个空指针转换为另一个指针类型会产生 该类型的空指针。任何两个空指针应比较 平等。
现在它只声明
(originaltype*)((void*)ptr) == ptr
永远是真的,但呢
(void*) ptr == ptr
没有明确说明这是真的还是假的。还是我误解了 1 段?
C 2018 6.5.9 讨论了==
.第 2 段指定了约束,(void *) ptr == ptr
满足约束条件,因为其中一个选项是"一个操作数是指向对象类型的指针,另一个是指向void
的限定或非限定版本的指针"。然后第5段说"...如果一个操作数是指向对象类型的指针,另一个操作数是指向 void 的限定或非限定版本的指针,则前者将转换为后者的类型。
因此,在(void *) ptr == ptr
中,右操作数被转换为(void *)
,所以表达式等价于(void *) ptr == (void *) ptr
,我们可以期望它的计算结果为真。
严格来说,指针转换的子句 6.3.2.3 只告诉我们将(void *) ptr
转换回其原始类型的结果将等于ptr
。它没有告诉我们关于(void *) ptr
值的任何其他信息,因此,仅考虑此子句,两个不同的(void *) ptr
实例可能会产生不同的结果,只要它们包含足够的信息来产生与转换回来时与原始ptr
相等的东西。
回到 6.5.9,第 6 段告诉我们:
两个指针比较相等,当且仅当两者都是空指针,两者都是指向同一对象的指针(包括指向对象的指针和其开头的子对象)或函数,两者都是指向一个经过同一数组对象的最后一个元素的指针,或者一个是指向一个数组对象末尾的指针,另一个是指向不同数组对象开头的指针这恰好紧跟在地址空间中的第一个数组对象之后。
现在,我们当然希望(void *) ptr == (void *) ptr
至少在某些时候是正确的。这怎么可能?(void *) ptr
不是空指针(假设ptr
不是),我们也不期望这种情况被一个数组的结尾和另一个情况的开头所涵盖。因此,我们希望,当(void *) ptr == (void *) ptr
计算为 true 时,一定是因为它处于"指向同一对象的指针"或"指向同一数组对象案例的最后一个元素的指针"中。这似乎是解释标准的唯一合理方式。如果是这样,那么这种情况(无论哪种情况有时适用)必须始终适用,而"当且仅当"告诉我们(void *) ptr == (void *) ptr
总是正确的。
*如果ptr
是指向对象类型的指针,则(void *) ptr == ptr
等效于(void *) ptr == (void *) ptr
。 右侧的ptr
隐式转换为void *
。(如果它是指向const
或volatile
限定类型的指针,则这些限定符在隐式转换中丢失。
(void *) ptr
当然等于它自己,除非我们接受闲散的幽默,比如ptr
是一个宏观扩展到一个有副作用的表达,在不同的评估中改变其价值,或者是一个不确定价值的表达,其使用是未定义的行为。
如果ptr
是指向函数的指针,那么(void *) ptr == ptr
需要诊断;但很明显,讨论是关于对象类型的。