You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++是否保证指针转换为其他指针类型时表示具有一致性?

答复

核心结论

C++标准不保证任意指针类型转换后内部表示完全一致,不同转换场景的规则差异极大,我们结合你提供的测试代码逐一说明对应行为的标准约定:

#include <stdint.h>

struct Foo {};
struct Bar : Foo {};

int main() {
    Bar obj;

    Foo * a = &obj;
    Bar * b = &obj;
    void *c = &obj;
#if MAYBE_UB
    int * d = reinterpret_cast<int *>(&obj);
#endif

    auto aa = reinterpret_cast<uintptr_t>(a);
    auto bb = reinterpret_cast<uintptr_t>(b);
    auto cc = reinterpret_cast<uintptr_t>(c);
#if MAYBE_UB
    auto dd = reinterpret_cast<uintptr_t>(d); // UB? Not reading the pointee...
#endif

    if (aa != bb) printf("bb differs\n");
    if (aa != cc) printf("cc differs\n");
#if MAYBE_UB
    if (aa != dd) printf("dd differs\n");
#endif

    return 0;
}

分场景规则说明

1. 派生类指针转非虚基类指针(对应Foo *a = &obj;)

  • 你示例中的Foo是Bar的非虚空基类,二者都属于标准布局类型:

    C++标准明确要求:标准布局类型的对象,其起始地址与所有非虚基类子对象的起始地址完全重合。该场景下aa == bb是被标准强制保证成立的。

  • 如果不符合标准布局要求(比如继承链存在虚函数、虚继承、基类和派生类都声明了非静态数据成员等),基类子对象在派生类的内存布局中会存在偏移,此时转换后的基类指针值会和原派生类指针值不同,aa != bb属于合法实现。
  • 空基类优化(EBCO)是当前所有主流编译器的默认行为,生产环境中几乎不会出现该场景下两个指针值不等的情况。

2. 对象指针转void*(对应void *c = &obj;)

  • 标准明确规定:任意对象指针转换为cv void*类型时,得到的指针指向该对象的起始存储地址。
  • 因此该场景下cc == bb是100%被标准保证成立的,不存在实现差异。

3. 用reinterpret_cast转不相关类型的对象指针(对应int *d = reinterpret_cast<int *>(&obj);)

  • 首先明确:仅做指针类型转换、不解引用指向的内存的行为不属于未定义行为(UB),仅属于结果未指定。
  • 标准对reinterpret_cast的指针转换仅做了最低约束:将T1*转换为T2*再转换回T1*时,指针值保持不变。没有对中间转换得到的T2*的指针值做任何强制要求。
  • 因此dd == aa是否成立完全取决于编译器实现,标准没有任何约定。主流x86、ARM平台的编译器通常会保持指针值不变,但不能跨平台、跨编译器做通用假设。

测试程序行为总结

  • 关闭MAYBE_UB宏的情况下:标准布局场景下aa == bb成立,aa == cc始终成立,不会打印任何输出。
  • 开启MAYBE_UB宏的情况下:aa == dd没有标准保证,是否打印dd differs由编译器实现决定。

内容的提问来源于stack exchange,提问作者Thomas Eding

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 22:27:01