应使用 reinterpret_cast 将 uintptr_t 转为 void,而非 static_cast 或 int;因 void 与 int 类型语义不兼容,且 int 在64位系统易截断地址,必须经 uintptr_t 中转以确保安全。

直接用 reinterpret_cast 转,别用 static_cast
整数转 void* 不是类型兼容转换,C++ 标准不保证 static_cast<void>(n)</void> 合法——它只接受指针到指针的转换。真正能跨类型的只有 reinterpret_cast,而且必须确保整数足够大(比如 uintptr_t)来存下指针值。
-
int通常太小(32 位),在 64 位系统上无法安全存地址,强行转可能截断高位,运行时崩溃或静默出错 - 正确做法是先转成
uintptr_t(定义在<cstdint></cstdint>),再用reinterpret_cast<void></void> - 反向转换(
void*→ 整数)也必须走uintptr_t,不能直接转int
示例:
uintptr_t addr_val = 0x123456789ABCDEF0ULL; void* p = reinterpret_cast<void*>(addr_val); // ✅ 安全
为什么 void* 不能直接接收 int 值
因为 void* 是对象指针类型,语义上代表“某个内存地址的起始位置”,而 int 是算术类型。C++ 类型系统严格区分这两类,编译器不会隐式做这种解释性转换——这不是精度问题,是语义越界。
- 用
static_cast<void>(42)</void>会编译失败(GCC/Clang 都报错) - 用 C 风格
(void*)42虽能过,但等价于reinterpret_cast,且掩盖了类型意图,不推荐 - Windows 上
LONG_PTR、Linux 上intptr_t也是可选,但uintptr_t是标准、无符号、更符合“地址值”本意
实际用在哪儿?常见场景和风险点
这种转换几乎只出现在底层互操作中:比如 Windows 的 SetWindowLongPtr 存句柄、POSIX 线程传参、某些回调函数的 void* 用户数据字段。不是日常逻辑该碰的东西。
立即学习“C++免费学习笔记(深入)”;
- 把一个计数器
int i = 5直接转成void*传给线程函数,然后在线程里当指针解引用 —— 必崩,这不是合法地址 - 如果真要传整数值,应该传地址:
pthread_create(..., &i),而不是reinterpret_cast<void>(i)</void> - Qt 的
QObject::setProperty或信号槽传参完全不需要手动转,别硬套这个模式
64 位系统下最常踩的坑
开发机是 64 位,但用 int 或 long(在 macOS/Linux 上仍是 32 位)存地址值,转出来只有低 4 字节有效,高半段全丢。
- 检查方式:
static_assert(sizeof(uintptr_t) == sizeof(void*), "uintptr_t must match pointer size"); - 不要依赖
long:Windows 64 位下long是 32 位,Linux/macOS 是 64 位,不可移植 - 如果必须用带符号类型,用
intptr_t,但注意负值地址极少合法,uintptr_t更直白
地址值不是整数,只是恰好能用整数表示;把它当整数运算(比如加减偏移)前,务必确认原始来源确实是有效指针。










