Lun*_*din 12 c pointers casting initialization assignment-operator
这个问题旨在成为整数和指针问题之间所有初始化/分配的常见问题解答条目。
我想编写代码,将指针设置为特定的内存地址,例如0x12345678. 但是当用 gcc 编译器编译这段代码时,我得到“初始化使指针从整数而不进行强制转换”警告/错误:
int* p = 0x12345678;
Run Code Online (Sandbox Code Playgroud)
类似地,这段代码给出了“初始化从指针生成整数而不进行强制转换”:
int* p = ...;
int i = p;
Run Code Online (Sandbox Code Playgroud)
如果我在变量声明行之外做同样的事情,消息是一样的,但说的是“赋值”而不是“初始化”:
p = 0x12345678; // "assignment makes pointer from integer without a cast"
i = p; // "assignment makes integer from pointer without a cast"
Run Code Online (Sandbox Code Playgroud)
使用其他流行编译器的测试也会给出错误/警告消息:
int不能用于初始化类型的实体int*”int*在间接级别上与int”不同。问题:上面的例子是有效的 C 吗?
还有一个后续问题:
这不会给出任何警告/错误:
int* p = 0;
Run Code Online (Sandbox Code Playgroud)
为什么不?
Lun*_*din 13
不,它不是有效的 C 并且从来都不是有效的 C。这些例子是所谓的违反标准的约束。
该标准不允许您初始化/分配指向整数的指针,也不允许您初始化/分配指向指针的整数。您需要使用强制转换手动强制类型转换:
int* p = (int*) 0x1234;
int i = (int)p;
Run Code Online (Sandbox Code Playgroud)
如果您不使用强制转换,则代码不是有效的 C,并且您的编译器不允许在不显示消息的情况下让代码通过。具体来说,这是由简单分配规则,C17 6.5.16.1 §1 规定的:
6.5.16.1 简单赋值
约束
符合下列条件之一:
在 的情况下int* p = 0x12345678;,左操作数是指针,右操作数是算术类型。
在 的情况下int i = p;,左操作数是算术类型,右操作数是指针。
这些都不符合上述任何约束条件。
至于为什么int* p = 0;有效,这是一个特例。左操作数是一个指针,右操作数是一个空指针常量。有关空指针、空指针常量和 NULL 宏之间区别的更多信息。
一些注意事项:
如果将原始地址分配给指针,则该指针可能需要volatile限定,因为它指向硬件寄存器或 EEPROM/闪存位置之类的东西,可以在运行时更改其内容。
即使使用强制转换,也不能保证将指针转换为整数。标准(C17 6.3.2.3 §5 和 §6 说):
整数可以转换为任何指针类型。除了前面指定的,结果是实现定义的,可能没有正确对齐,可能不指向引用类型的实体,并且可能是陷阱表示。68)
任何指针类型都可以转换为整数类型。除了前面指定的,结果是实现定义的。如果结果不能以整数类型表示,则行为未定义。结果不必在任何整数类型的值范围内。
信息性脚注:
68)将指针转换为整数或将整数转换为指针的映射函数旨在与执行环境的寻址结构保持一致。
此外,来自指针的地址可能大于 可以容纳在 中的地址int,大多数 64 位系统就是这种情况。因此最好使用uintptr_tfrom<stdint.h>