指向不同对象的指针的相等性比较

abl*_*igh 5 c language-lawyer

受此问题回答的启发,我对C11和C99标准进行了深入研究,以在指针上使用相等运算符(原始问题涉及关系运算符)。以下是§6.5.9.6中C11所说的(C99类似):

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

脚注94说(并且请注意,脚注是非规范性的):

两个对象可能在内存中相邻,这是因为它们是较大数组的相邻元素或结构的相邻成员,并且它们之间没有填充,或者是因为实现方式选择放置它们,即使它们是不相关的。如果先前的无效指针操作(例如,在数组范围之外进行访问)产生了未定义的行为,则后续的比较也将产生未定义的行为。

文本的正文和非规范性注释似乎存在冲突。如果人们认真对待案文中的“ if and only if”,那么除规定的情况外,其他情况下均不得返回均等,UB也没有余地。因此,例如此代码:

uintptr_t a = 1;
uintptr_t b = 1;
void *ap = (void *)a;
void *bp = (void *)b;
printf ("%d\n", ap <= bp); /* UB by §6.5.8.5 */
printf ("%d\n", ap < bp);  /* UB by §6.5.8.5 */
printf ("%d\n", ap == bp); /* false by §6.5.9.6 ?? */
Run Code Online (Sandbox Code Playgroud)

应该打印零,因为apbp既不是指向同一对象或函数的指针,也不是其他列出的任何位。

在第6.5.8.5节(关系运算符)中,行为更加清晰(我强调):

比较两个指针时,结果取决于所指向对象的地址空间中的相对位置。如果两个指向对象或不完整类型的指针都指向同一个对象,或者都指向一个指向同一数组对象的最后一个元素的指针,则它们比较相等。如果所指向的对象是同一聚合对象的成员,则指向稍后声明的结构成员的指针大于指向早于结构中声明的成员的指针,指向具有较大下标值的数组元素的指针大于指向同一数组的元素的指针下标值较低。指向同一联合对象的成员的所有指针比较相等。如果表达式P指向数组对象的元素,则表达式Q指向同一数组对象的最后一个元素,指针表达式的Q+1比较大于P在所有其他情况下,行为是不确定的。

问题:

  • 我是正确的,关于何时允许使用带指针的相等运算符UB(比较脚注和正文)有一些歧义?

  • 如果没有歧义,那么什么时候可以将指针与相等运算符进行比较精确到UB?例如,如果至少人工创建了一个指针(是否按上),是否总是UB?如果一个指针指向已经存在的内存free()d怎么办?给定脚注是非规范性的,是否可以得出结论,就所有“其他”比较都必须产生意义而言,永远不会存在UB false

  • §6.5.9.6真的意味着无意义但按位相等的指针的相等比较应始终为假吗?

请注意,这个问题被标记为;我不是在问编译器在做什么,因为我相信已经知道了答案(使用与比较整数相同的技术比较它们)。

Okt*_*ist -1

关于带指针的等式运算符何时为 UB 存在一些歧义,我是否正确?

\n\n

不,因为这段来自 \xc2\xa76.5.9(3):

\n\n
\n

and运算符==!=关系运算符类似,只是它们的优先级较低。

\n
\n\n

意味着 \xc2\xa76.5.9(6) 中的以下内容也适用于相等运算符:

\n\n
\n

当比较两个指针时[...]在所有其他情况下,行为是未定义的。

\n
\n\n

如果没有歧义,那么指针与相等运算符的比较到底什么时候可以是UB?

\n\n

在标准未明确定义行为的所有情况下,都存在未定义的行为。

\n\n

如果至少有一个指针是 UB 吗?人工创造的从任意整数转换?

\n\n

\xc2\xa76.3.2.3(5):

\n\n
\n

整数可以转换为任何指针类型。除非前面指定,否则结果是实现定义的,可能未正确对齐,可能不指向引用类型的实体,并且可能是陷阱表示。

\n
\n\n

如果一个指针指向已经被freed过的内存怎么办?

\n\n

\xc2\xa76.2.4(2):

\n\n
\n

当指针指向的对象到达其生命周期结束时,指针的值变得不确定。

\n
\n\n

从所有“其他”比较都必定产生错误的意义上来说,我们可以得出永远不存在 UB 的结论吗?

\n\n

不可以。该标准定义了在什么条件下两个指针必须比较相等,以及在什么条件下两个指针必须比较不相等。超出这两组条件的两个指针之间的任何相等比较都会调用未定义的行为。

\n\n

\xc2\xa76.5.9(6) 是否真的意味着无意义但按位相等的指针的相等比较应该始终为 false?

\n\n

不,它是未定义的。

\n

  • 没有投反对票,但是出于 §6.5.9(6) 的目的,`==` 和 `!=` 属于比较运算符,这是最没有说服力的。§6.5.8(5)(当比较两个指针时...)位于关系运算符下(不包括 == 和 !=),与我类似并不意味着 §6.5.8(5) 应该适用,并且如果不相关对象的相等比较是 UB,那么比较 fn 指针之类的事情将是 UB,这似乎有问题。 (3认同)
  • 我不是反对者,但你的回答未能解决 6.5.9/6 的问题。该问题的关键点之一是 6.5.9/6 是否应该将相等比较的适用性扩展到关系比较所允许的范围之外。您似乎声称 6.5.9/3 胜过 6.5.9/6。这没有说服力。 (2认同)