【问题标题】:Is the equality relation of pointers after round-trip conversion guaranteed to be transitive?往返转换后指针的相等关系是否保证传递?
【发布时间】:2021-11-09 18:54:25
【问题描述】:

这个问题类似于“Are all pointers guaranteed to round-trip through void * correctly?”,但更深一些。

给定:

#include <stdint.h>
int i;
int *ip1 = &i;
void *vp1 = ip1;
intptr_t x = (intptr_t)vp1;
void *vp2 = (void *)x;
int *ip2 = vp2;

那么vp1 == vp2 保证为真(即使它们可能不共享相同的二进制表示),但ip1 == ip2 保证为真?即,在这种情况下,等式关系是否传递?

【问题讨论】:

    标签: c pointers language-lawyer void-pointers


    【解决方案1】:

    保证此转换有效。

    首先,从对象指针到void * 的转换在C standard 的第6.3.2.3p1 节中描述:

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

    其次,从void *intptr_t 的转换在第 7.20.1.4p1 节中描述:

    以下类型指定带符号的整数类型 任何指向void 的有效指针都可以转换为的属性 这个类型,然后转换回指向void的指针,然后 结果将等于原始指针:

    intptr_t
    

    以下类型指定无符号整数类型 任何指向void 的有效指针都可以转换为的属性 这个类型,然后转换回指向void的指针,然后 结果将等于原始指针:

    uintptr_t
    

    这些类型是可选的。

    在这种情况下,int * (ip1) 转换为 void * (vp1),void * 转换为 intptr_t

    intptr_t 被转换回void * (vp2)。到 7.20.1.4p1,vp2 必须比较等于 vp1

    然后vp2 被转换为int * (ip2)。由于vp2vp1 相同,所以将vp2 转换为int * 等效于将vp1 转换为int *,因此将产生一个比较等于ip1 的指针根据 6.3.2.3p1。

    【讨论】:

    • 我想我要问的是是否有可能通过这个转换链最终得到两个指向同一个对象但比较不相等的指针。
    • 所以从技术上讲“指针比较在传递时是传递的”
    • 只是为了确认,关于转换规则,隐式转换和显式转换之间有区别吗? void *intptr_t 标准中的解释使用相同的术语(“已转换”),但问题中的代码明确转换了变量 x 的使用。
    • @sj95126 没有区别。 6.3p1:*“几个运算符自动将操作数值从一种类型转换为另一种类型。本子条款规定了这种隐式转换所需的结果,以及强制转换操作(显式转换)产生的结果。”
    • @dbush:好的,所以代码中的演员表不需要在那里?我不是在批评代码,只是想确定我理解为什么有些转换有强制转换而另一些没有。
    【解决方案2】:

    无论出处如何,指针相等的传递性都遵循相等运算符的规范。 C 2018 6.5.9 6 说:

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

    忽略空指针和函数指针,这在此处不是问题,鉴于 a == bb == c 评估为真,它们必须满足规范中列出的条件之一,因此我们有以下情况:

    Given a == b. Given b == c. a == c?
    a and b both point to the same object . b and c both point to the same object. a and c both point to the same object. Therefore a == c evaluates as true.
    a and b both point to the same object. c points to one past the last element of an array object and b points to the start of an array object that happens to follow it. c points to one past the last element of an array object and a points to the start of an array object that happens to follow it. Therefore a == c evaluates as true.
    a and b both point to one past the last element of the same array object. b and c both point to one past the last element of the same array object. a and c both point to one past the last element of the same array object. Therefore a == c evaluates as true.
    a points to one past the last element of an array object and b points to the start of an array object that follows it. b and c both point to the same object. a points to one past the last element of an array object and c points to the start of an array object that follows it. Therefore a == c evaluates as true.
    b points to one past the last element of an array object and a points to the start of an array object that follows it. b and c both point to one past the last element of an array object. c points to one past the last element of an array object and a points to the start of an array object that follows it. Therefore a == c evaluates as true.

    请注意,b 不会指向第一列中的对象,也不会指向第二列中数组的最后一个元素,反之亦然:无论是这两种指针中的哪一种,它a == bb == c 中的类型必须相同。

    【讨论】:

    • a 指向数组对象最后一个元素之后的一个元素,b 指向其后一个数组对象的开头。”不一定是真的,因为一些编译器会跟踪指针的出处。见stackoverflow.com/questions/45966762/…
    • @dbush:这是一个语言律师问题。这就是 C 标准所说的。
    • 谢谢。我对 6.5.9/6 深信不疑,因为指向 int 的两个指针必须指向同一个 int 对象(如果您认为一个对象由字节大小的子对象组成,并且两个指针都指向 void在通过intptr_t 的往返之前和之后必须指向相同int 对象开头的相同字节),那么它们必须比较相等。
    猜你喜欢
    • 1970-01-01
    • 2015-05-04
    • 1970-01-01
    • 2014-06-17
    • 2019-03-20
    • 2018-11-16
    • 2022-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多