c-是保证可传递的往返转换后指针的相等关系



这个问题类似于"是否所有指针都保证通过void*进行往返"但是稍微深一点。

给定:

#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标准:的第6.3.2.3p1节中描述了从对象指针到void *的转换

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

第二,从void *intptr_t的转换在第7.20.1.4p1:节中进行了描述

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

intptr_t

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

uintptr_t

这些类型是可选的。

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

将CCD_ 18转换回CCD_ 19(vp2)。通过7.20.1.4p1,vp2必须与vp1进行比较。

然后CCD_ 23被转换为CCD_ 24(ip2)。由于vp2vp1相同,因此vp2int *的转换等效于vp1int *的转换,因此将产生一个指针,该指针将根据6.3.2.3p1与ip1进行比较。

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

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

取消空指针和指向函数的指针,这在这里不是问题,假设a == bb == c的值为true,它们必须满足规范中列出的条件之一,因此我们有以下情况:

给定a == b 给定CCD_ 36 a == c
ab都指向同一对象 bc都指向同一对象 ac都指向同一对象。因此a == c评估为真
ab都指向同一对象 c指向数组对象的最后一个元素后的一个,b指向恰好跟随它的数组对象的开始。 c指向数组对象最后一个元件后的一,void0指向恰好跟随其后的数组对象开始。因此,a == c的计算结果为true
ab都指向同一数组对象的最后一个元素之后的一个 bc都指向同一数组对象的最后一个元素之后的一个 ac都指向同一数组对象的最后一个元素之后的一个。因此a == c评估为真
a指向数组对象最后一个元素后的一个元素,b指向其后的数组对象的开头。 bc都指向同一对象 a指向数组对象的最后一个元素后的一个,c指向它后面的数组对象的开头。因此a == c的计算结果为true
b指向数组对象最后一个元素后的一个,a指向它后面的数组对象的开始。 bc都指向数组对象的最后一个单元后的一 c指向数组对象最后一个元素后的一个元素,a指向它后面的数组对象的开头。因此a == c计算为true