我对reinterpret_cast和static_cast的适用性有点困惑。根据我所读到的,一般规则是当类型可以在编译时解释时使用静态强制转换,因此是静态这个词。这也是c++编译器内部用于隐式类型转换的类型转换。
reinterpret_cast适用于以下两种情况:
将整数类型转换为指针类型,反之亦然
将一种指针类型转换为另一种。我得到的一般想法是,这是不可移植的,应该避免。
我有点困惑的地方是我需要的一种用法,我从C调用c++, C代码需要保持c++对象,所以基本上它持有一个void*。在void *和Class类型之间应该使用什么类型转换?
我已经看到使用static_cast和reinterpret_cast?虽然从我所读到的似乎静态更好,因为强制转换可以在编译时发生?虽然它说使用reinterpret_cast从一种指针类型转换为另一种?
简单的回答是:
如果你不知道reinterpret_cast代表什么,就不要使用它。如果你将来需要它,你会知道的。
完整的回答:
让我们考虑基本的数字类型。
例如,当你将int(12)转换为unsigned float (12.0f)时,你的处理器需要调用一些计算,因为这两个数字具有不同的位表示。这就是static_cast所代表的内容。
另一方面,当你调用reinterpret_cast时,CPU不会调用任何计算。它只是把内存中的一组位当作另一种类型来处理。因此,当你用这个关键字将int*转换为float*时,新值(指针解引用后)在数学意义上与旧值没有任何关系(忽略读取该值是未定义行为的事实)。
请注意,在reinterprt_cast'ing之后读取或修改值通常是未定义的行为。在大多数情况下,如果你想实现一些数据的位表示,你应该使用指向std::byte的指针或引用(从c++ 17开始),这几乎总是一个合法的操作。其他“安全”的类型是char和unsigned char,但我认为在现代c++中不应该将其用于此目的,因为std::byte具有更好的语义。
Example: It is true that reinterpret_cast is not portable because of one reason - byte order (endianness). But this is often surprisingly the best reason to use it. Let's imagine the example: you have to read binary 32bit number from file, and you know it is big endian. Your code has to be generic and works properly on big endian (e.g. some ARM) and little endian (e.g. x86) systems. So you have to check the byte order. It is well-known on compile time so you can write constexpr function: You can write a function to achieve this:
/*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 '0000(小端)。重新解释后,p指针下的字节可以分别为0000'0000或0000'0001。如果使用静态强制转换,则无论使用什么字节顺序,它都将始终是0000'0001。
编辑:
在第一个版本中,我让示例函数is_little_endian为constexpr。它在最新的gcc(8.3.0)上编译良好,但标准说它是非法的。clang编译器拒绝编译它(这是正确的)。
首先你有一些特定类型的数据,比如这里的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
or
float y = *(float*)&(x);
//this could be used in c and cpp
BRIEF:这意味着相同的内存被用作不同的类型。所以你可以像上面那样将浮点数的二进制表示形式转换为int类型。例如,0x80000000为-0(尾数和指数为空,但符号msb为1。这也适用于双打和长双打。
优化:我认为reinterpret_cast会在许多编译器中进行优化,而c-casting是由指针算术进行的(值必须复制到内存中,因为指针不能指向cpu-寄存器)。
注意:在这两种情况下,您都应该在强制转换之前将强制转换的值保存在变量中!这个宏可以帮助:
#define asvar(x) ({decltype(x) __tmp__ = (x); __tmp__; })