2010-02-05 119 views
46

据我所知,reinterpret_cast是危险的,我只是这样做来测试它。我有以下代码:为什么不能编译reinterpret_cast?

int x = 0; 
double y = reinterpret_cast<double>(x); 

当我试图编译程序,它给了我一个错误说

invalid cast from type 'float' to type 'double 

这是怎么回事?我以为reinterpret_cast是你可以用来将苹果转换成潜艇的流氓演员,为什么这个简单的演员不能编译?

+0

我从来没有在C++中试过这个,所以我只是猜测。它是否工作,如果你投的浮动?难道不是这两种类型的位长不同? – 2010-02-05 06:13:19

+0

“'reinterpret_cast (x)'”你预计这个表达要做什么? – curiousguy 2012-07-25 15:58:08

+2

int是32位。双是64位。这可能是问题。你可以检查一下吗? – 2012-09-23 16:27:37

回答

34

通过由投返回的值赋给ÿ你并没有真正投入价值x,你正在转换它。也就是说,y不指向x并假装它指向一个浮点数。转换构造一个新的值float,并从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; 
} 

唯一的区别是最后一个(隐式转换),将产生一个编译器上更高的警告级别的诊断。但他们都在功能上做同样的事情 - 在很多情况下,实际上是一样的东西,在相同的机器代码。

现在,如果你真的想假装x是float,那么你真的要投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。

+0

will(float)x返回42或某些不相关double的二进制表示。我认为这个人意味着重新解释,那就是他想要的。 – 2012-09-23 16:26:35

+0

'(float)x'将执行转换,而不是转换。 – 2012-09-23 22:09:31

+0

您的代码下面是严格的锯齿违规,因此具有未定义的行为。 – 2017-10-25 23:41:36

1

reinterpret_cast最适合用于指针。所以指向一个对象的指针可以变成一个“潜艇”。

msdn

reinterpret_cast运算符可用于转化如char *到 INT *,或* One_class到 Unrelated_class *,这是固有 不安全 。

一个的reinterpret_cast 的结果不能安全地用于任何 不是被转换回其原来 其他类型。其他用途在 最好,不便携。

0

将int投射到double不需要投射。编译器将隐含地执行分配。

reinterpret_cast与指针和引用一起使用,例如将int *转换为double *

7

如果你想你的int到一个double的代表性位转换,你需要转换地址不是值。您还必须确保尺寸匹配:

uint64_t x = 0x4045000000000000; 
double y = *reinterpret_cast<double *>(&x); 
0

这很有趣。也许它在从int到float的转换之前进行隐式转换,然后再尝试转换为double。 int和float类型的字节大小相同(当然取决于你的系统)。

3

编译器拒绝你写的废话,因为intdouble可能是具有不同大小的对象。你可以达到同样的效果这样,虽然它肯定是危险的:

int x = 0; 
double y = *reinterpret_cast<double*>(&x); 

这是潜在的危险,因为如果xy是不同势的大小(假设int是四个字节,并将double是八个字节),那么你的时候在解引用的&x八个字节的内存来填补y您将访问四个字节的x和四个字节的......在记忆最终会发生什么(的y可能启动,或垃圾,或别的东西完全。)

如果你想转换一个intege r加倍,使用static_cast,它将执行转换。

如果您要访问的x的位模式,投给了一些方便的指针类型(比如,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] 
} 
+2

不是编译器拒绝它的原因,但关于字体大小的讨论是有价值的。 – 2010-02-05 09:06:32

11

reinterpret_cast不是一般演员。根据C++ 03规范第5.2.10.1节:

下面列出了可以使用reinterpret_cast明确执行的转换。没有其他转换可以使用reinterpret_cast显式执行。

并没有列出什么,说明整数和浮点类型之间的转换(或整型之间,即使这是非法的reinterpret_cast<long>(int(3));

2

重释投可以让你重新诠释的内存块为不同类型的。这必须在指针或引用进行:

int x = 1; 
float & f = reinterpret_cast<float&>(x); 
assert(static_cast<float>(x) != f); // !! 

的另一件事是,它实际上是一个相当危险的演员,这不仅是因为陌生值出来的结果,或断言上面没有失败,但是因为如果类型的大小不同,并且您从“源”到“目标”类型重新解释,则对重新解释的引用/指针的任何操作都将访问sizeof(destination)字节。如果sizeof(destination)>sizeof(source)然后,将步骤超出了实际可变存储器,有可能杀死你的应用程序或overwritting比源或目的地以外的其他变量:

struct test { 
    int x; 
    int y; 
}; 
test t = { 10, 20 }; 
double & d = reinterpret_cast<double&>(t.x); 
d = 1.0/3.0; 
assert(t.x != 10); // most probably at least. 
asswet(t.y != 20); 
34

在C++ reinterpret_cast只能执行一组特定的转换,在明确列出语言规范。简而言之,reinterpret_cast只能执行指针到指针的转换和参考到引用的转换(加上指针到整数和整数到指针的转换)。这与演员的名字所表达的意图是一致的:它意在用于指针/参考重新解释。

你试图做的不是重新解释。如果你想重新诠释的intdouble你必须将其转换为引用类型

double y = reinterpret_cast<double&>(x); 

虽然相当于基于指针的重新解释可能是更明确的

double y = *reinterpret_cast<double*>(&x); // same as above 

不过请注意,而reinterpret_cast可以转换引用/指针类型,实际尝试通过结果引用/指针读取数据会产生未定义的行为。

在任何情况下这一点,当然也没有多大意义的平台上int和不同尺寸的double(因为在大double情况下,你会读超出x占用的内存)。

所以,最后,这一切都归结为你想要达到的目标。记忆重新解释?往上看。某种更有意义的intdouble转换?如果是这样,reinterpret_cast不会帮你在这里。

+0

'reinterpret_cast只能执行指针到指针的转换和引用到引用的转换(加上指针到整数和整数到指针的转换)''这个问题变得平坦了,可以被接受为答案。 – 2017-07-08 15:09:17