【问题标题】:Any real example of reinterpret_cast changing a pointer value?reinterpret_cast 更改指针值的任何真实示例?
【发布时间】:2011-03-18 22:42:35
【问题描述】:

根据 C++ 标准,指针 T*reinterpret_cast 指向其他类型的指针 Q* can change or not change the pointer value,具体取决于实现。

我很感兴趣 - 是否有任何 C++ 实现的真实示例,其中使用 reinterpret_cast 将指针转换为其他指针类型会更改指针?那里发生了什么变化以及为什么发生变化?

【问题讨论】:

  • 你的意思是,指针指向的“改变值”?
  • @akira: 不,改变指针本身的值
  • 你的意思是:T* t = 0x13; Q* q = 0x42; t = reintrepret_cast<Q*>(q); 产生 t != 0x42?
  • @akire:我猜是的。我自己也不确定,这就是我问的原因。您可能有兴趣阅读链接问题的答案 - 它们启发了我提出这个问题。
  • 所以你不确定你在问什么? :) 我认为删除的答案是由于问题有点不清楚。是的,链接的问题很有趣。

标签: c++ compiler-construction casting


【解决方案1】:

请注意,当标准声明它可以或不可能做某事时,这并不意味着当前有任何实现具有该行为,只是它们可以。

我能想到的最接近的是硬件需要类型对齐的架构,以及决定在需要时纠正对齐的实现。比如:

aligned8 var;
aligned1 *p = reinterpret_cast<aligned1*>(&var);
aligned1 *q = p + 1; // assuming aligned 1 size is not multiple of 8
aligned8 *a = reinterpret_cast<aligned8*>(q); // [1]

可能要求a 是一个有效的指针,它必须寻址8 倍的内存位置,而具有较少对齐要求的参数q 可以指向任何内存地址。

【讨论】:

    【解决方案2】:
    class A1 { int a1; };
    class A2 { int a2; };
    
    class B: public A1, public A2 { };
    
    #define DBG(val)  cout << #val << ": " << val << endl
    
    // test code
    B b;
    DBG(&b);                                           // prints 0x42
    
    void *p_blank = &b;
    DBG(p_blank);                                      // prints 0x42
    A2 *p_a2 = &b; 
    DBG(p_a2);                                         // prints 0x46
    void *p_reinterpreted = reinterpret_cast<A2*>(&b);
    DBG(p_reinterpreted);                              // prints 0x42
    A2 *p_reinterpreted2 = reinterpret_cast<A2*>(&b);
    DBG(p_reinterpreted2);                             // prints 0x42
    

    A2 *p_a2 = &amp;b 表示给我指向 B 对象中的 A2 对象的指针reinterpret_cast&lt;A2*&gt;(&amp;b) 表示 给我指向 b 的指针并将其视为 A2 指针。 此 reinterpret_cast 的结果具有“指向 A2 的指针”类型,因此在分配给 void* 变量(或 A2* 变量)时不会产生警告。

    【讨论】:

    • 在您的示例中,reinterpret_cast 根本不会更改值...恐怕您已经离开了。
    • A2 *p_a2 = &amp;b; 中,您使用的隐式转换等效于static_cast,而不是reinterpret_cast
    • 看来我没有正确理解这个问题。我了解到您正在搜索 reinterpret_cast 返回与空白“地址”运算符不同的值的情况。我在 C++ 标准中没有找到允许 reinterpret_cast 与 reinterpret_cast 不同的子句。
    • @akira:当您对基指针进行隐式向上转换(或static_cast)时,返回的指针是该基的子类在对象中的地址。当您使用第一个碱基时,地址会重合。如果存在多重继承,向上转换到除第一个基类之外的所有基类(假设第一个基类不为空)将产生偏移的指针。在这个特定的示例中,A1 类正好占用 4 个字节。
    【解决方案3】:

    Reinterpret_cast 永远不会返回不同的地址 - 需要复制确切的地址。

    在多重继承的情况下,就像 David Rodriguez 所说的那样,获取其中一个基址的地址可能会返回一个与第一个基址的地址有偏移的地址。 Reinterpret_cast 会返回那个偏移地址,但是如果你把它当作上播地址,地狱就会接踵而至。

    对于向上转换,static_cast 可以返回与给定地址不同的地址。如果您拥有的地址是其中一个基地址,并且该地址与第一个基地址有偏移,则 static_cast 将为向上转换的对象返回一个有效地址,该地址等于第一个基地址的地址,因此不等于指向传递的指针。

    简而言之:reinterpret_cast 始终为您提供相同的地址。 Static_cast 和 dynamic_cast 可能返回不同的地址,例如在某些涉及多重继承的情况下。

    static_cast 和 dynamic_cast 的区别在于 static_cast 不检查你给它的指针是否是正确的对象,所以在调用它之前要确定。

    【讨论】:

    • 涉及“必需”的语句应有来源备份。我所看到的是,您可以转换为不太严格对齐类型的指针然后返回,并且“任何其他此类指针转换的结果都是未指定的”。 (5.2.10/7)
    • 嗯,我完全错过了对齐问题,我可以看到这将如何改变地址。谢谢指正。
    【解决方案4】:

    最可能的问题来源是向量机,其中标量操作是根据向量定义的,而标量指针由指向向量的指针和向量的索引组成。从历史上看,最初的 Cray 架构是这样的,它引起了头疼。现在你可能会在 GPU 上看到类似的东西,但我无法指出具体的东西。

    最可能的影响是截​​断,因为目标指针类型缺少指定索引部分的位。 C++11 通过允许任何指针类型为reinterpret_casted,只要它们具有相同的对齐要求,就朝这个方向点头。允许严格对齐“归零”的位不存在。

    对象指针可以显式转换为对象指针 一种不同的类型。当“指向 T1 的指针”类型的纯右值 v 是 转换为“指向 cv T2 的指针”类型,如果 T1 和 T2 都是标准布局,则结果为 static_cast<cv T2*>(static_cast<cv void*>(v)) types (3.9) 和T2的对齐要求不严格 T1 的那些, 或者如果任何一种类型都是无效的。转换类型的prvalue “指向 T1 的指针”指向类型“指向 T2 的指针”(其中 T1 和 T2 是 对象类型和 T2 的对齐要求没有 比 T1 更严格)并返回其原始类型产生 原始指针值。任何其他此类指针的结果 转换未指定。

    【讨论】:

      【解决方案5】:

      我认为 C++ 与 C 指针转换的问题并没有明显的不同。来自this answer,我只引用其中一个例子:

      Data General 的 Eclipse MV 系列具有三种体系结构支持的指针格式(字、字节和位指针),其中两种被 C 编译器使用:字节指针用于 char*void*,字指针用于其他的

      这表明reinterpret_cast&lt;Word_Aligned_Type*&gt;(char*) 可能会失去它所指向的单词中的哪个字符/字节,从而使操作不可逆转。

      【讨论】:

        猜你喜欢
        • 2017-06-16
        • 2018-07-17
        • 1970-01-01
        • 2021-07-26
        • 2020-03-12
        • 2016-06-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多