唯一标准且可移植的方式是用 reinterpret_cast,需先存入 uintptr_t 再转换;硬编码地址仅适用于嵌入式寄存器访问或 mmap 映射后偏移,否则导致段错误或未定义行为。

直接用 reinterpret_cast 转换整数地址为指针
在 C++ 中,把一个固定数值地址(比如 0x1000)变成可用的指针,唯一标准且可移植的方式是用 reinterpret_cast。C 风格的强制转换(如 (int*)0x1000)虽能编译,但行为未定义,且现代编译器常报 -Wold-style-cast 警告。
正确写法:
uintptr_t addr = 0x1000; int* p = reinterpret_cast<int*>(addr);
- 必须用
uintptr_t(定义在<cstdint>)来存地址值,它保证能容纳指针位宽;用int或long在 64 位系统上可能截断 - 目标类型(如
int*)需与实际内存中数据类型一致,否则读写会触发未定义行为 - 该操作本身不检查地址是否有效——访问前必须确保该地址确实可读/可写,且已映射到当前进程空间
访问硬件寄存器或 mmap 内存时才真正需要它
普通应用几乎从不需要硬编码地址。只有两类场景合理:
- 嵌入式开发中操作特定外设寄存器(如 ARM 的
0x400FE000对应 GPIO 控制器) - 用户态程序通过
mmap()映射设备文件(如/dev/mem)或共享内存后,拿到内核返回的起始地址再偏移计算
例如 Linux 下读取物理地址(需 root 权限):
立即学习“C++免费学习笔记(深入)”;
int fd = open("/dev/mem", O_RDWR | O_SYNC);
void* mem = mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x1000);
int* p = static_cast<int*>(mem); // 此时 mem 是合法映射地址,不是硬编码
注意:直接用 reinterpret_cast 指向未映射地址(如 0x1000)会导致段错误(Segmentation fault),不是“指针没生效”,而是 CPU MMU 拒绝访问。
编译器不会帮你检查地址合法性
即使代码能编译通过,也不代表运行安全。常见误判包括:
- 地址对齐错误:比如用
int*指向奇数地址,在 ARM 或 RISC-V 上直接触发Bus error - 权限错误:只读内存区域用
const int*声明也无用,写操作仍会崩溃;必须匹配mmap()时指定的PROT_WRITE - ASLR 干扰:硬编码地址在启用地址空间布局随机化(ASLR)的系统上必然失效,仅适用于裸机或关闭 ASLR 的调试环境
调试建议:用 /proc/self/maps 查看进程实际映射的内存范围,确认目标地址是否落在某段 rw- 区域内。
替代方案:优先用符号名代替硬编码地址
除非绝对必要,避免手写十六进制地址。更健壮的做法是:
- 链接脚本中定义符号(如
_io_base),让链接器填入真实地址,C++ 里用extern "C" char _io_base;+&_io_base获取 - 驱动通过
ioctl或 sysfs 向用户态返回动态分配的寄存器基址 - 使用平台抽象层(如 HAL 库)封装地址访问,隐藏底层细节
硬编码地址等于把硬件拓扑耦合进应用逻辑,一旦芯片型号变更或寄存器重排,所有相关指针都要手动改——这种脆弱性比语法细节更值得警惕。


















