C在转换后的指针上的相等运算符

Aco*_*orn 10 c pointers language-lawyer

将整数常量转换为指针类型

从这个问题,我们从6.3.2.3p5(C11)知道,我们可以将任何整数转换为指针(即,它本身不是UB):

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

然后,从6.5.9p6开始,我们有:

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

因此,似乎我们可以在没有UB的情况下应用相等运算符(与关系运算符不同)。考虑:

struct A;

int f(void) {
    struct A * a = (struct A *) 1;
    struct A * b = (struct A *) 1;
    return a == b;
}
Run Code Online (Sandbox Code Playgroud)

假设的地址中没有A对象,则可能会争辩说应该返回,因为没有条件与上述条件匹配。a1f()false

如何反驳?即使没有对象,“指向同一对象的指针”是否也指向地址(无论如何,编译器也不知道)?我们是否应该简单地理解它是实现定义的,因为先前的结果已经是实现定义的?标准在哪里指定?

true正如预期的那样,所有主要的编译器都返回上述代码。

Joh*_*ger 7

如何反驳?即使没有对象,“指向同一对象的指针”是否也指向地址

不,我认为这不是一个合理的阅读。如果您规定指针值不是指向对象的指针(并且它不是空指针),则该(指针)值与自身的相等比较不满足“仅当”条件6.5.9 / 6,因此比较必须求值为0。

但是没有那么快。谁说那(struct A *) 1不是指向对象的指针?考虑标准对“对象”的定义:


执行环境中数据存储的对象区域,其内容可以表示值

C 2011,3.15 / 1

注意,该定义并不固有地限于由程序分配或声明的对象。就我所知,该标准无处以这种方式限制该术语的范围。它确实定义了分配对象的方法,但没有指定以那些方式之一分配的对象是唯一存在的对象。因此,实现可以自由地将指针值解释为指向对象的指针,在这种情况下,相等性比较的结果可能为1。

尽管两个指针(大概)具有按位表示形式,但它仍可能等于1,但不一定将它们视为指向同一对象的指针。

(不像编译器可以知道的那样)?

当然,编译器可以并且应该知道。它必须知道以便评估您所呈现的表达式。最直接的方法(并非巧合的是,最常见的方法)是将不是陷阱表示形式的每个非空指针值解释为指向对象的指针。

我们是否应该简单地理解它是实现定义的,因为先前的结果已经是实现定义的?

定义为实现时,需要遵循实现以记录其选择。您要询问的行为可能来自将整数转换为指针的实现定义的行为,但它本身不是实现定义的。

标准在哪里指定?

没有指定。原则上,符合的实现可能在这一点上有所不同。但是在实践中,它们是非常一致的。

  • 还请注意委员会对[C缺陷报告260](http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_260.htm)的答复,其中委员会认为:“ [实施]即使它们按位相同,也可能会将基于不同来源的指针视为不同。” 可以将其视为适用于示例情况,因此,该标准也未指定。 (2认同)
  • 该示例在不同的优化级别下表现出不同的行为并不能证明该代码具有UB。如果它的行为只是未指定的行为(如该代码那样),则可能会发生同样的情况。 (2认同)