何时使用重新解释

我对reinterpret_cast vs static_cast的适用性感到困惑。 从我读过的一般规则来看,当编译时可以解释类型时使用静态转换,因此使用static 。 这是C ++编译器内部用于隐式强制转换的强制转换。

reinterpret_cast s适用于两种情况,将整数类型转换为指针类型,反之亦然,或将一种指针类型转换为另一种类型。 我得到的一般想法是不可移植的,应该避免。

我有点困惑的地方是我需要的一种用法,我从C调用C ++,C代码需要保持C ++对象,所以它基本上保留了void* 。 应该使用什么转换来在void *和Class类型之间进行转换?

我看到static_castreinterpret_cast用法了? 尽管从我一直在阅读的内容来看, static效果更好,因为在编译时可以发生剧情? 虽然它说使用reinterpret_cast从一种指针类型转换到另一种指针类型?


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只保证,如果你将一个指针指向一个不同的类型,然后reinterpret_castreinterpret_cast回原来的类型,你会得到原始值。 所以在下面:

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

a和c包含相同的值,但b的值未指定。 (在实际中,它通常包含与a和c相同的地址,但标准中没有说明这一点,在具有更复杂存储系统的机器上可能不是这样)。

对于从void *进行投射,应首选static_cast


reinterpret_cast有必要的一种情况是与不透明数据类型进行交互。 这经常发生在程序员无法控制的供应商API中。 以下是供应商提供用于存储和检索任意全局数据的API的一个人为的示例:

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

要使用此API,程序员必须将其数据转换为VendorGlobalUserData并返回。 static_cast不起作用,必须使用reinterpret_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; }

简短的回答:如果您不知道reinterpret_cast代表什么,请不要使用它。 如果将来需要它,你会知道的。

完整答案:

我们来考虑基本的数字类型。

当你将int(12)转换为unsigned float (12.0f)你的处理器需要调用一些计算,因为两个数字都有不同的位表示。 这就是static_cast代表的意思。

另一方面,当你调用reinterpret_cast ,CPU不会调用任何计算。 它只处理内存中的一组位,就像它有另一种类型一样。 所以当你用这个关键字将int*转换为float*时,新的值(在取消指针后)与数学意义上的旧值没有任何关系。

例子: reinterpret_cast确实不可移植,因为一个原因 - 字节顺序(字节顺序)。 但这通常是令人惊讶的使用它的最好理由。 让我们想象一下这个例子:你必须从文件中读取二进制的32位数字,并且你知道它是大端的。 您的代码必须是通用的,并且可以在大端(如ARM)和小端(如x86)系统上正常工作。 所以你必须检查字节顺序。 它在编译时很有名,所以你可以编写constexpr函数:

constexpr bool is_little_endian() {
  unsigned short x=0x0001;
  auto p = reinterpret_cast<unsigned char*>(&x);
  return *p != 0;
}

说明:内存中x的二进制表示可能是0000'0000'0000'0001 (大)或0000'0001'0000'0000 (小端)。 重新0000'0000p指针下的字节可以分别为0000'00000000'0001 。 如果您使用静态铸造,无论使用哪种字节顺序,它总是为0000'0001

链接地址: http://www.djcxy.com/p/12811.html

上一篇: When to use reinterpret

下一篇: Casting vs using the 'as' keyword in the CLR