3

我从上一个问题中删除了这个问题,因为我认为这是一个相当个人的问题。所以我在标准中找到了指针转换的段落,关于我的问题的段落是:

6.3.2.3

指针

1 指向 void 的指针可以转换为指向任何对象类型的指针或从指向任何对象类型的指针转​​换。指向任何对象类型的指针都可以转换为指向 void 的指针并再次返回;结果应与原始指针比较。

...

4 将空指针转换为另一种指针类型会产生该类型的空指针。任何两个空指针应该比较相等。

现在它只说

(originaltype*)((void*)ptr) == ptr

将永远是真实的,但那又如何

(void*) ptr == ptr

没有明确说明这是对还是错。还是我误解了第 1 段?

4

2 回答 2

4

C 2018 6.5.9 讨论==。第 2 段指定了约束,并(void *) ptr == ptr满足约束,因为其中一个选项是“一个操作数是指向对象类型的指针,另一个是指向限定或非限定版本的指针void”。然后第 5 段说“……如果一个操作数是指向对象类型的指针,而另一个是指向 void 的限定或非限定版本的指针,则前者将转换为后者的类型。”</p>

因此,在 中(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计算结果为真时,一定是因为它处于“指向同一对象的指针”的情况下或“指向同一数组对象最后一个元素的指针的情况”。这似乎是解释标准的唯一合理方式。如果是这样,那么这种情况(无论哪种情况有时适用)必须始终适用,并且“当且仅当”告诉我们这(void *) ptr == (void *) ptr始终是正确的。

于 2019-06-09T01:12:49.747 回答
1

*Ifptr是指向对象类型的指针 then(void *) ptr == ptr等价于(void *) ptr == (void *) ptr. ptr右边的 被隐式转换为void *。(如果它是指向constvolatile限定类型的指针,则这些限定符会在隐式转换中丢失。)

(void *) ptr肯定等于它自己,除非我们接受闲散的幽默,例如ptr将宏扩展为具有副作用的表达式,从而在不同的评估中改变其值,或者是一个不确定值的表达式,其使用是未定义的行为。

如果ptr是指向函数的指针,则(void *) ptr == ptr需要诊断;但很明显,讨论是关于对象类型的。

于 2019-06-09T06:36:38.360 回答