这个问题类似于"是否所有指针都保证通过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
)。由于vp2
与vp1
相同,因此vp2
到int *
的转换等效于vp1
到int *
的转换,因此将产生一个指针,该指针将根据6.3.2.3p1与ip1
进行比较。
指针的等式传递性,无论出处如何,都遵循等式运算符的规范。C 2018 6.5.9 6说:
两个指针比较相等,当且仅当两者都是空指针,都是指向同一对象(包括指向对象的指针和位于其开头的子对象)或函数的指针,都指向同一数组对象最后一个元素后的指针,或者一个是指向经过一个数组对象末尾的一个数组的指针,另一个是指恰好紧跟在地址空间中的第一个数组对象之后的不同数组对象的开头的指针。
取消空指针和指向函数的指针,这在这里不是问题,假设a == b
和b == c
的值为true,它们必须满足规范中列出的条件之一,因此我们有以下情况:
给定a == b |
给定CCD_ 36 | a == c |
---|---|---|
a 和b 都指向同一对象 |
b 和c 都指向同一对象 |
a 和c 都指向同一对象。因此a == c 评估为真 |
a 和b 都指向同一对象 |
c 指向数组对象的最后一个元素后的一个,b 指向恰好跟随它的数组对象的开始。 |
c 指向数组对象最后一个元件后的一,void 0指向恰好跟随其后的数组对象开始。因此,a == c 的计算结果为true |
a 和b 都指向同一数组对象的最后一个元素之后的一个 |
b 和c 都指向同一数组对象的最后一个元素之后的一个 |
a 和c 都指向同一数组对象的最后一个元素之后的一个。因此a == c 评估为真 |
a 指向数组对象最后一个元素后的一个元素,b 指向其后的数组对象的开头。 |
b 和c 都指向同一对象 |
a 指向数组对象的最后一个元素后的一个,c 指向它后面的数组对象的开头。因此a == c 的计算结果为true |
b 指向数组对象最后一个元素后的一个,a 指向它后面的数组对象的开始。 |
b 和c 都指向数组对象的最后一个单元后的一 |
c 指向数组对象最后一个元素后的一个元素,a 指向它后面的数组对象的开头。因此a == c 计算为true |