指针与intptr_t/uintptr_t互转时的类型转换方式选择及函数指针与对象指针的差异
指针与intptr_t/uintptr_t互转时的类型转换方式选择及函数指针与对象指针的差异
嘿,这个问题问到点子上了!我之前在项目里刚好踩过相关的坑,来给你掰扯明白~
一、对象指针和intptr_t/uintptr_t互转的情况
首先得明确:intptr_t和uintptr_t这俩类型就是专门设计用来存储对象指针数值的,所以这里的首选绝对是reinterpret_cast,原因很实在:
- C++标准明确规定,用
reinterpret_cast把对象指针转成intptr_t/uintptr_t,再转回到原来的指针类型,结果会完全等于原指针,合法且安全,是标准给的“官方指定转换方式”。 - 哪怕碰到小众平台,对象指针的位表示和整数类型有差异,
reinterpret_cast也会按标准要求处理转换逻辑,保证正确性。
那std::bit_cast呢?它是C++20才有的新特性,核心是直接按位复制内存内容。如果你的平台上对象指针和intptr_t/uintptr_t大小完全相同,且都是平凡可复制类型,它确实能跑起来,但有个致命隐患:标准没有保证对象指针的位模式和intptr_t的位模式是一一对应的。虽然主流x86、ARM平台没问题,但万一碰到奇葩架构,指针位表示有特殊编码,bit_cast转出来的整数再转回去可能就不是原指针了,属于未定义行为。
总结:对象指针和这俩整数类型互转,优先用reinterpret_cast,稳得一批。
二、函数指针的情况
这里就得敲黑板划重点了,和对象指针完全不是一回事!
- 首先,C++标准根本没规定函数指针可以转换为
intptr_t/uintptr_t!换句话说,用reinterpret_cast把函数指针转成这俩整数类型,本身就是未定义行为。为啥?因为有些平台(比如部分嵌入式分段架构)的函数指针大小比对象指针大,intptr_t根本装不下它的完整数值。 - 那
std::bit_cast呢?它要求源类型和目标类型大小必须完全相同,否则直接编译报错。如果你的平台上函数指针和intptr_t大小刚好一致,bit_cast能完成按位复制,但标准同样没保证转回去的函数指针是合法可调用的——函数指针的位模式可能包含特殊信息(比如段选择符),不是简单的整数数值,强行调用大概率会崩溃或者出现诡异行为。
所以函数指针的情况:尽量别想着转成intptr_t/uintptr_t!如果非得存函数指针的“数值”,优先用void(*)(void)这种通用函数指针类型来存储,而不是整数类型。真要转的话,也得先确认你的平台明确支持这种操作(比如POSIX有相关规定,但不属于C++标准),这时候bit_cast至少能保证位复制正确,但依然有风险。
备注:内容来源于stack exchange,提问作者user541686
相关产品推荐
相关产品推荐

