代码之家  ›  专栏  ›  技术社区  ›  HeretoLearn

何时使用reinterpret_cast?

  •  388
  • HeretoLearn  · 技术社区  · 17 年前

    reinterpret_cast static_cast . 从我所读到的内容来看,当类型可以在编译时被解释时,一般的规则是使用静态强制转换 static . 这是C++编译器内部使用的用于隐式转换的强制转换。

    s适用于两种情况:

    • 将整数类型转换为指针类型,反之亦然
    • 将一种指针类型转换为另一种。我的总体想法是,这是不可移植的,应该避免。

    void* . 应使用哪种类型转换在 void *

    静态浇铸 重新解释 ? 虽然从我所读到的来看 静止的 在编译时进行强制转换更好吗?虽然上面说要用 从一种指针类型转换为另一种指针类型?

    10 回复  |  直到 5 年前
        1
  •  496
  •   leiyc    6 年前

    C++标准保证如下:

    static_cast 正在从中删除指向和来自的指针 void* 保留地址。就是在下面,, a b c

    int* a = new int();
    void* b = static_cast<void*>(a);
    int* c = static_cast<int*>(b);
    

    reinterpret_cast 仅保证如果将指针强制转换为其他类型, 重新解释 它恢复到原来的类型 ,则得到原始值。因此,在以下方面:

    int* a = new int();
    void* b = reinterpret_cast<void*>(a);
    int* c = reinterpret_cast<int*>(b);
    

    B 没有具体说明。(实际上,它通常包含的地址与 A. C ,但该标准中没有规定,并且在具有更复杂内存系统的计算机上可能不适用。)

    用于来回浇铸 空虚* , 静态浇铸 应优先考虑。

        2
  •  175
  •   jwfearn    11 年前

    一例 reinterpret_cast

    // vendor.hpp
    typedef struct _Opaque * VendorGlobalUserData;
    void VendorSetUserData(VendorGlobalUserData p);
    VendorGlobalUserData VendorGetUserData();
    

    要使用此API,程序员必须将其数据强制转换为 VendorGlobalUserData 然后再回来。 static_cast 重新解释

    // main.cpp
    #include "vendor.hpp"
    #include <iostream>
    using namespace std;
    
    struct MyUserData {
        MyUserData() : m(42) {}
        int m;
    };
    
    int main() {
        MyUserData u;
    
            // store global data
        VendorGlobalUserData d1;
    //  d1 = &u;                                          // compile error
    //  d1 = static_cast<VendorGlobalUserData>(&u);       // compile error
        d1 = reinterpret_cast<VendorGlobalUserData>(&u);  // ok
        VendorSetUserData(d1);
    
            // do other stuff...
    
            // retrieve global data
        VendorGlobalUserData d2 = VendorGetUserData();
        MyUserData * p = 0;
    //  p = d2;                                           // compile error
    //  p = static_cast<MyUserData *>(d2);                // compile error
        p = reinterpret_cast<MyUserData *>(d2);           // ok
    
        if (p) { cout << p->m << endl; }
        return 0;
    }
    

    下面是示例API的人为实现:

    // vendor.cpp
    static VendorGlobalUserData g = 0;
    void VendorSetUserData(VendorGlobalUserData p) { g = p; }
    VendorGlobalUserData VendorGetUserData() { return g; }
    
        3
  •  141
  •   Mariusz Jaskółka    7 年前

    简单的回答是: reinterpret_cast 代表,不要使用它。如果你将来需要它,你就会知道。

    完整答案:

    例如,当您转换 int(12) unsigned float (12.0f) 处理器需要调用一些计算,因为两个数字具有不同的位表示形式。这是什么 static_cast 代表。

    int* float* 有了这个关键字,新值(指针去引用后)在数学意义上与旧值无关。

    例子: 无法移植,原因只有一个-字节顺序(endianness)。但令人惊讶的是,这往往是使用它的最佳理由。让我们想象一下这个例子:您必须从文件中读取二进制32位数字,并且您知道它是big-endian。您的代码必须是通用的,并且在大端(例如某些ARM)和小端(例如x86)系统上正常工作。所以你必须检查字节顺序。 它在编译时是众所周知的,因此您可以编写 constexpr 功能:

    /*constexpr*/ bool is_little_endian() {
      std::uint16_t x=0x0001;
      auto p = reinterpret_cast<std::uint8_t*>(&x);
      return *p != 0;
    }
    

    的二进制表示 x 在记忆中可能是 0000'0000'0000'0001 (大)或 0000'0001'0000'0000 (小恩迪安)。重新解释后,将字节强制转换为 p 指针可以分别为 0000'0000 0000'0001 . 如果你使用静态铸造,它将永远是 0000'0001 ,无论使用什么endianness。

    编辑:

    在第一个版本中,我创建了示例函数 is_little_endian 成为 常量表达式

        4
  •  21
  •   flodin    17 年前

    reinterpret_cast 不是由C++标准定义的。因此,在理论上 重新解释 可能会使你的程序崩溃。在实践中,编译器会尝试执行您期望的操作,即解释您要传递的内容的位,就好像它们是您要转换到的类型一样。如果您知道将要使用的编译器的功能 重新解释 你可以用它,但是说它是 便携式的 那是在撒谎。

    重新解释 static_cast 或者其他替代方案。除其他事项外,标准还规定了您可以期望的内容 (§5.2.9):

    因此,对于您的用例,标准化委员会打算让您使用它似乎是相当清楚的 .

        5
  •  10
  •   Adam P. Goucher    10 年前

    reinterpret_cast的一个用途是,如果您想对(IEEE 754)浮点应用位运算。其中一个例子是快速平方根逆技巧:

    https://en.wikipedia.org/wiki/Fast_inverse_square_root#Overview_of_the_code

    float Q_rsqrt( float number )
    {
        long i;
        float x2, y;
        const float threehalfs = 1.5F;
    
        x2 = number * 0.5F;
        y  = number;
        i  = * ( long * ) &y;                       // evil floating point bit level hacking
        i  = 0x5f3759df - ( i >> 1 );               // what the deuce? 
        y  = * ( float * ) &i;
        y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration
    //  y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed
    
        return y;
    }
    

    这最初是用C编写的,所以使用C转换,但是类似的C++ CAST是RealTytPraseCask。

        6
  •  3
  •   Intrastellar Explorer    5 年前

    这是Avi Ginsburg程序的一个变体,它清楚地说明了 reinterpret_cast

    #include <iostream>
    #include <string>
    #include <iomanip>
    using namespace std;
    
    class A
    {
    public:
        int i;
    };
    
    class B : public A
    {
    public:
        virtual void f() {}
    };
    
    int main()
    {
        string s;
        B b;
        b.i = 0;
        A* as = static_cast<A*>(&b);
        A* ar = reinterpret_cast<A*>(&b);
        B* c = reinterpret_cast<B*>(ar);
        
        cout << "as->i = " << hex << setfill('0')  << as->i << "\n";
        cout << "ar->i = " << ar->i << "\n";
        cout << "b.i   = " << b.i << "\n";
        cout << "c->i  = " << c->i << "\n";
        cout << "\n";
        cout << "&(as->i) = " << &(as->i) << "\n";
        cout << "&(ar->i) = " << &(ar->i) << "\n";
        cout << "&(b.i) = " << &(b.i) << "\n";
        cout << "&(c->i) = " << &(c->i) << "\n";
        cout << "\n";
        cout << "&b = " << &b << "\n";
        cout << "as = " << as << "\n";
        cout << "ar = " << ar << "\n";
        cout << "c  = " << c  << "\n";
        
        cout << "Press ENTER to exit.\n";
        getline(cin,s);
    }
    

    其结果如下所示:

    as->i = 0
    ar->i = 50ee64
    b.i   = 0
    c->i  = 0
    
    &(as->i) = 00EFF978
    &(ar->i) = 00EFF974
    &(b.i)   = 00EFF978
    &(c->i)  = 00EFF978
    
    &b = 00EFF974
    as = 00EFF978
    ar = 00EFF974
    c  = 00EFF974
    Press ENTER to exit.
    

    可以看出,B对象首先作为B特定的数据构建在内存中,然后是嵌入的A对象。这个 static_cast 正确返回嵌入对象的地址,以及由 正确给出数据字段的值。由生成的指针 b

    重新解释 是将指针转换为无符号整数(当指针和无符号整数大小相同时):

    int i; unsigned int u = reinterpret_cast<unsigned int>(&i);

        7
  •  2
  •   Community Mohan Dere    9 年前

    您可以使用reinterprete_cast在编译时检查继承。
    Using reinterpret_cast to check inheritance at compile time

        8
  •  1
  •   jwfearn    13 年前
    template <class outType, class inType>
    outType safe_cast(inType pointer)
    {
        void* temp = static_cast<void*>(pointer);
        return static_cast<outType>(temp);
    }
    

    我试图总结并使用模板编写了一个简单的安全转换。 请注意,此解决方案不保证在函数上强制转换指针。

        9
  •  1
  •   cmdLP    9 年前

    首先,这里有一些特定类型的数据,如int:

    int x = 0x7fffffff://==nan in binary representation
    

    然后,您希望访问与其他类型(如float)相同的变量:

    float y = reinterpret_cast<float&>(x);
    
    //this could only be used in cpp, looks like a function with template-parameters
    

    float y = *(float*)&(x);
    
    //this could be used in c and cpp
    

    优化:我认为在许多编译器中,reinterpret_cast会得到优化,而c-cast是由PointerArtihmetic实现的(值必须复制到内存中,因为指针不能指向cpu寄存器)。

    注意:在这两种情况下,您都应该在强制转换之前将强制转换的值保存在变量中!此宏可以帮助:

    #define asvar(x) ({decltype(x) __tmp__ = (x); __tmp__; })
    
        10
  •  -7
  •   MD XF    9 年前

    快速回答:使用 static_cast 如果它编译了,否则就求助于 reinterpret_cast .

        11
  •  -17
  •   MD XF    9 年前

    阅读 FAQ ! 在C中保存C++数据可能会带来风险。

    void * 没有任何石膏。但反过来说,情况并非如此。你需要一个 static_cast 获取原始指针。