c - "Pointer from integer/integer from pointer without a cast" issues
问题描述
This question is meant to be a FAQ entry for all initialization/assignment between integer and pointer issues.
I want to do write code where a pointer is set to a specific memory address, for example 0x12345678
. But when compiling this code with the gcc compiler, I get "initialization makes pointer from integer without a cast" warnings/errors:
int* p = 0x12345678;
Similarly, this code gives "initialization makes integer from pointer without a cast":
int* p = ...;
int i = p;
If I do the same outside the line of variable declaration, the message is the same but says "assignment" instead of "initialization":
p = 0x12345678; // "assignment makes pointer from integer without a cast"
i = p; // "assignment makes integer from pointer without a cast"
Tests with other popular compilers also give error/warning messages:
- clang says "incompatible integer to pointer conversion"
- icc says "a value of type
int
cannot be used to initialize an entity of typeint*
" - MSVC (cl) says "initializing
int*
differs in levels of indirection fromint
".
Question: Are the above examples valid C?
And a follow-up question:
This does not give any warnings/errors:
int* p = 0;
Why not?
解决方案
不,它不是有效的 C,而且从来都不是有效的 C。这些示例是所谓的违反标准的约束。
该标准不允许您初始化/分配指向整数的指针,也不允许将整数指向指针。您需要使用强制转换手动强制类型转换:
int* p = (int*) 0x1234;
int i = (int)p;
如果您不使用强制转换,则代码不是有效的 C,并且您的编译器不允许在不显示消息的情况下让代码通过。演员表操作员状态:C17 6.5.4/3:
约束
/--/
涉及指针的转换,除了 6.5.16.1 的约束允许的情况外,应通过显式强制转换来指定。
6.5.16.1 是允许指针的某些隐式转换的简单赋值规则,参见 C17 6.5.16.1 §1:
6.5.16.1 简单赋值
约束
应满足下列条件之一:
- 左操作数具有原子、合格或非限定算术类型,右操作数具有算术类型;
- 左操作数具有与右操作数兼容的结构或联合类型的原子、限定或非限定版本;
- 左操作数具有原子、限定或非限定指针类型,并且(考虑左操作数在左值转换后将具有的类型)两个操作数都是指向兼容类型的限定或非限定版本的指针,并且左侧指向的类型具有所有右边指向的类型的限定符;
- 左操作数具有原子、限定或非限定指针类型,并且(考虑左操作数在左值转换后将具有的类型)一个操作数是指向对象类型的指针,另一个是指向限定或非限定版本的指针void,并且left指向的类型具有right指向的类型的所有限定符;
- 左操作数是原子的、合格的或不合格的指针,右操作数是空指针常量;或者
- 左操作数的类型为 atomic、qualified 或 unqualified _Bool,而右操作数是指针。
在 的情况下int* p = 0x12345678;
,左操作数是指针,右操作数是算术类型。
在 的情况下int i = p;
,左操作数是算术类型,右操作数是指针。
这些都不符合上述任何限制条件。
至于为什么int* p = 0;
有效,这是一个特例。左操作数是指针,右操作数是空指针常量。有关空指针、空指针常量和 NULL 宏之间区别的更多信息。
一些注意事项:
如果将原始地址分配给指针,则可能需要
volatile
限定指针,因为它指向硬件寄存器或 EEPROM/闪存位置之类的东西,可以在运行时更改其内容。即使使用强制转换,也不能保证将指针转换为整数。标准(C17 6.3.2.3 §5 和 §6 说):
整数可以转换为任何指针类型。除非前面指定,结果是实现定义的,可能没有正确对齐,可能不指向引用类型的实体,并且可能是陷阱表示。68)
任何指针类型都可以转换为整数类型。除非前面指定,结果是实现定义的。如果结果不能以整数类型表示,则行为未定义。结果不必在任何整数类型的值范围内。
内容丰富的脚注:
68)将指针转换为整数或将整数转换为指针的映射函数旨在与执行环境的寻址结构保持一致。
此外,指针的地址可能比 . 中的地址要大int
,大多数 64 位系统就是这种情况。因此最好使用uintptr_t
from<stdint.h>
推荐阅读
- python - 如何使用sharex = True在catplot(kind ='violin')的顶部对seaborn catplot(kind ='count')进行子图
- php - 如何使用基于数据库条目 ID 的 PHP 从 MySQL 数据库中提取数据
- mongodb - findoneandupdate 和重复错误 11000
- visual-studio-code - 无论如何要摆脱 VSCode IDE 中的这个视图?
- javascript - 为什么我的 CSS3 媒体查询不起作用?
- firebase-realtime-database - 使用与未来异步的侦听器加载 firebase 数据库列表
- javafx - javafx ListView上的selectFirst()不选择元素
- javascript - 如何使用 Chai 在 mocha 框架中使用 backstopjs 断言失败
- c# - Xamarin C# 的 AWS Cognito 登录问题
- c - 为什么这个矩阵乘法算法比另一个更快?