为什么不这reinterpret_cast编译?
我明白reinterpret_cast是危险的,我只是做这个来testing它。 我有以下代码:
int x = 0; double y = reinterpret_cast<double>(x);
当我尝试编译程序时,它给我一个错误说
invalid cast from type 'float' to type 'double
这是怎么回事? 我以为reinterpret_cast是你可以用来将苹果转换成潜艇的stream氓演员,为什么这个简单的演员不能编译?
通过将y分配给演员返回的值,您并不是真正投射值x
,而是将其转换。 也就是说, y
不指向x
并假装它指向一个浮点数。 转换构造一个新的float
types的值,并为其赋值x
。 有几种方法可以在C ++中进行这种转换,其中包括:
int main() { int x = 42; float f = static_cast<float>(x); float f2 = (float)x; float f3 = float(x); float f4 = x; return 0; }
唯一真正的区别是最后一个(隐式转换)将生成更高警告级别的编译器诊断。 但是他们都在function上做同样的事情 – 在许多情况下, 实际上是相同的东西,在相同的机器代码。
现在如果你真的想假装x
是一个浮点数,那么你真的想要这样做:
#include <iostream> using namespace std; int main() { int x = 42; float* pf = reinterpret_cast<float*>(&x); (*pf)++; cout << *pf; return 0; }
你可以看到这有多危险 事实上,当我在我的机器上运行这个输出时,输出是1
,这决不是42 + 1。
在C ++中, reinterpret_cast
只能执行一组特定的转换,在语言规范中明确列出。 简而言之, reinterpret_cast
只能执行指针到指针的转换和引用到引用的转换(加上指针到整数和整数到指针的转换)。 这与演员的名字所expression的意图是一致的:意图用于指针/参考重新解释。
你试图做的不是重新解释。 如果你想重新解释一个int
为double
你必须将其转换为引用types
double y = reinterpret_cast<double&>(x);
尽pipe等价的基于指针的重新解释可能更加明确
double y = *reinterpret_cast<double*>(&x); // same as above
请注意虽然reinterpret_cast
可以转换参考/指针types,但实际尝试通过生成的参考/指针读取数据会产生未定义的行为。
在任何情况下,当然,在一个int
和double
大小不同的平台上(因为在double
情况下,你会读取x
以上的内存)。
所以最终都归结为你想要达到的目标。 内存重新解释? 往上看。 一些更有意义的int
double
转换? 如果是这样, reinterpret_cast
不会帮你在这里。
reinterpret_cast不是一般的演员。 根据C ++ 03规范第5.2.10.1节:
下面列出了可以使用reinterpret_cast明确执行的转换。 使用reinterpret_cast不能显式执行其他转换。
并没有列出任何描述在整型和浮点types之间转换(或整型之间的转换,即使这是非法的reinterpret_cast<long>(int(3));
)
如果你想把int
的位转换成double
的表示forms,你需要把地址转换成不是这个值。 您还必须确保尺寸匹配:
uint64_t x = 0x4045000000000000; double y = *reinterpret_cast<double *>(&x);
编译器拒绝你写的东西是无稽之谈,因为int
和double
可能是不同大小的对象。 你可以用这种方法达到同样的效果,虽然这肯定是危险的:
int x = 0; double y = *reinterpret_cast<double*>(&x);
这是潜在的危险,因为如果x
和y
是不同的大小(假设int
是四个字节, double
是八个字节),那么当你在&x
取消八个字节的内存填充时,你将访问四个字节的x
和四个字节…的内容(可能是y
的开始,或者垃圾,或者其他的东西)。
如果要将整数转换为double,请使用static_cast
并执行转换。
如果你想访问x
的位模式,可以使用一些方便的指针types(比如说byte*
),并访问sizeof(int) / sizeof(byte)
:
byte* p = reinterpret_cast<byte*>(&x); for (size_t i = 0; i < sizeof(int); i++) { // do something with p[i] }
重新解释转换允许您重新解释为不同types的内存块。 这必须在指针或引用上执行:
int x = 1; float & f = reinterpret_cast<float&>(x); assert( static_cast<float>(x) != f ); // !!
另一件事情是,这实际上是一个相当危险的演员,不仅是因为奇怪的价值观作为结果出现,或者上面断言没有失败,而是因为如果types是不同的大小,你重新解释从“源”到'destination'types,对重新解释的引用/指针的任何操作都将访问sizeof(destination)
字节。 如果sizeof(destination)>sizeof(source)
那么这将超出实际的variables内存,可能会导致应用程序中断或覆盖源或目标之外的其他variables:
struct test { int x; int y; }; test t = { 10, 20 }; double & d = reinterpret_cast<double&>( tx ); d = 1.0/3.0; assert( tx != 10 ); // most probably at least. asswet( ty != 20 );
reinterpret_cast
最适合用于指针。 所以指向一个对象的指针可以变成一个“潜艇”。
从msdn :
reinterpret_cast运算符可用于转换,如char *到int *或One_class *到Unrelated_class *,这本质上是不安全的。
reinterpret_cast的结果不能安全地用于除了被转换回原始types以外的其他任何东西。 其他用途充其量不适用。
将一个int转换为double不需要转换。 编译器将隐含地执行分配。
reinterpret_cast用于指针和引用,例如,将int *
转换为double *
。
那很有意思。 也许这是做一个从int到float的隐式转换,然后再试图转换成double。 int和floattypes的字节大小一样(取决于你的系统当然)。