rto*_*ala 5 c c++ language-lawyer
我对从指针到整数和各种相关操作的转换的定义性(未定义性、实现定义性)感兴趣。我主要对 C11 感兴趣,但欢迎其他标准版本(甚至 C++)的答案。
出于这个问题的目的,假设 C 实现提供了intptr_t.
考虑以下函数:
#include <assert.h>
#include <stdint.h>
int x;
int y;
int z[2];
void f1(void) {
int *p = &x;
intptr_t i = p;
}
void f2(void) {
int *p = &x;
intptr_t i1 = p;
intptr_t i2 = p;
assert(i1 == i2);
}
void f3(void) {
int *p1 = &x;
int *p2 = &y;
intptr_t i1 = p1;
intptr_t i2 = p2;
assert(i1 != i2);
}
void f4(void) {
int *p1 = &x;
intptr_t i1 = p1;
int *p2 = i1;
intptr_t i2 = p2;
assert(i1 == i2);
}
void f5(void) {
int *p1 = &z[0];
int *p2 = &z[1];
intptr_t i1 = p1;
intptr_t i2 = p2;
assert(i1 < i2);
}
Run Code Online (Sandbox Code Playgroud)
void*而不是有什么改变int*吗?任何其他数据类型作为指针的目标怎么样?int*tointptr_t和 back 的显式转换有什么变化吗?(因为 GCC 对演员表发出警告而询问。)asserts 保证永远不会触发?这是 C11 标准的规定intptr_t:
7.20.1.4 能够保存对象指针的整数类型
以下类型指定一个有符号整数类型,其属性是任何有效的指针 to 都
void可以转换为该类型,然后转换回指针 tovoid,结果将与原始指针进行比较:Run Code Online (Sandbox Code Playgroud)intptr_t
与此相同uintptr_t(除了签名 -> 未签名)。
同样来自“6.5.4p3 Cast Operators”:
除 6.5.16.1 的约束允许的情况外,涉及指针的转换应通过显式强制转换来指定。
其中 6.5.16.1 没有提到将指针分配给整数类型,反之亦然(0常量除外)。这意味着您在分配时确实需要强制转换,gcc 仅允许它作为编译器扩展(并且它根本不使用 进行编译-pedantic-errors)
至于这些转换中返回的确切值,标准是这样规定的:
6.3.2.3 指针
p5 整数可以转换为任何指针类型。除非前面指定,否则结果是实现定义的,[...]
p6 任何指针类型都可以转换为整数类型。除非前面指定,否则结果是实现定义的。[...]
您拥有的基本保证是:
intptr_t
Run Code Online (Sandbox Code Playgroud)
并且没有必要强制转换为相同的整数。例如,以下情况可能为真:
int x;
(int*) (void*) (intptr_t) (void*) &x == &x;
/* But the void* casts can be implicit */
(int*) (intptr_t) &x == &x;
Run Code Online (Sandbox Code Playgroud)
在必要时添加强制转换,并将断言转换为返回值(因为assert(false)是未定义的行为),您的函数都没有未定义的行为,但是f2,f4和f5可以为 false。f3必须为 true,因为两个整数必须不同才能转换为不同的指针。