往返转换后的指针的相等关系是否保证具有传递性?

Ian*_*ott 6 c pointers void-pointers language-lawyer

这个问题类似于“是否所有指针都保证正确地通过 void * 往返? ”,但稍微更深一些。

鉴于:

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

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

dbu*_*ush 6

此转换保证有效。

首先, C 标准void *第 6.3.2.3p1 节描述了对象指针与 a 之间的转换:

指向的指针void可以与指向任何对象类型的指针相互转换。指向任何对象类型的指针都可以转换为指向void或返回的指针;结果应等于原始指针

其次,第 7.20.1.4p1 节描述了从 avoid *到 a的转换:intptr_t

以下类型指定一个有符号整数类型,其属性是任何有效的指针 to 都void可以转换为该类型,然后转换回指针 to void,结果将与原始指针进行比较:

intptr_t
Run Code Online (Sandbox Code Playgroud)

以下类型指定一个无符号整数类型,其属性是任何有效的指针 to 都void可以转换为该类型,然后转换回指针 to void,结果将与原始指针进行比较:

uintptr_t
Run Code Online (Sandbox Code Playgroud)

这些类型是可选的。

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

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

然后vp2转化为int *( ip2)。由于vp2与 相同,因此tovp1的转换相当于将to转换为,因此将产生一个比较等于6.3.2.3p1 的指针。vp2int *vp1int *ip1


Eri*_*hil 5

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

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

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

鉴于a == b. 鉴于b == c. a == c
a并且b两者都指向同一个对象。 b并且c都指向同一个对象。 a并且c都指向同一个对象。因此a == c评估为 true。
a并且b都指向同一个对象。 c指向数组对象最后一个元素之后的一个,并b指向紧随其后的数组对象的开头。 c指向数组对象最后一个元素之后的一个,并a指向紧随其后的数组对象的开头。因此a == c评估为 true。
a两者b都指向同一数组对象的最后一个元素。 b两者c都指向同一数组对象的最后一个元素。 a两者c都指向同一数组对象的最后一个元素。因此a == c评估为 true。
a指向数组对象最后一个元素之后的一个,并b指向其后面的数组对象的开头。 b并且c都指向同一个对象。 a指向数组对象最后一个元素之后的一个,并c指向其后面的数组对象的开头。因此a == c评估为 true。
b指向数组对象最后一个元素之后的一个,并a指向其后面的数组对象的开头。 b两者c都指向数组对象最后一个元素之后的一个。 c指向数组对象最后一个元素之后的一个,并a指向其后面的数组对象的开头。因此a == c评估为 true。

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