是否有任何用例依赖于两个分配的整数表示在C中是不同的?
例如,请考虑以下C代码段:
void *p = malloc(1); void *q = malloc(1); bool question = (uintptr_t) p == (uintptr_t) q;
我希望每个人都希望question
永远是假的。 (令人惊讶的是,C11标准并不要求它。对uintptr_t
的唯一限制是例如((void *) ((uintptr_t) p)) == p
。有关详细信息,请参阅C11标准的7.20.1.4。)
我的问题是:是否有任何实际用例实际上依赖于保证question
是错误的,或者更一般地说,两个分配的整数表示是不同的?
这个问题有缺陷。 首先,考虑一下这段代码(我们假设malloc
不返回null):
void *p = malloc(1); void *q = malloc(1); bool question = (uintptr_t) p == (uintptr_t) q;
根据C 2011标准的uintptr_t
规范,如果我们这样做:
void *p1 = (void *) (uintptr_t) p; void *q1 = (void *) (uintptr_t) q;
那么p1
必须比较等于p
, q1
必须比较等于q
。 并且,根据==
运算符的标准规范, p1
和q1
不能相互比较,因为它们分别等于p
和q
,因此是指向不同对象的指针。
因为(void *) (uintptr_t) p
和(void *) (uintptr_t) q
产生不同的值, (uintptr_t) p
和(uintptr_t) q
必须是不同的值。 (这是因为转换为void *
是C模型中的一个数学函数。每次给定一个特定值,在C的规则内,它产生的结果实际上是相同的,在C的规则内。)因此(uintptr_t) p
不等于(uintptr_t) q
。
现在考虑这个代码,我们将void *
更改为char *
:
char *p = malloc(1); char *q = malloc(1); bool question = (uintptr_t) p == (uintptr_t) q;
uintptr_t
的规范没有提及char *
转换。 显然,这些指向char *
指针可以转换为void *
。 但是,我没有看到标准要求从char *
到uintptr_t
必须隐式地将转换插入void *
或者就像它一样。 所以我认为这在标准上在技术上是不确定的。 但是我怀疑你会发现任何与void *
版本不同的C实现,除了一个专门构造违反这个的实现。
尽管如此,有效地使用uintptr_t
每个程序员都希望结果完全识别原始指针(它包含要转换回原始指针的所有信息),因此他们期望uintptr_t
结果与所有不同指针的结果不同。
至于一个具体的例子,macOS中的Accelerate框架期望将不同指针转换为uintptr_t
结果产生不同的结果,我相信macOS的许多其他部分也会这样做。