为什么这个reinterpret_cast没有编译?

Vla*_*ala 62 c++ casting reinterpret-cast

我明白这reinterpret_cast很危险,我只是这样做来测试它.我有以下代码:

int x = 0;
double y = reinterpret_cast<double>(x);
Run Code Online (Sandbox Code Playgroud)

当我尝试编译程序时,它给我一个错误说

从'float'类型转换为'double'类型无效

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

Joh*_*ing 41

通过将y指定给转换返回的值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;
}
Run Code Online (Sandbox Code Playgroud)

唯一真正的区别是最后一个(隐式转换)将在更高的警告级别上生成编译器诊断.但它们在功能上都是相同的 - 在很多情况下实际上是相同的东西,就像在相同的机器代码中一样.

现在,如果你真的想假装它x是一个浮点数,那么你真的想要x通过这样做来强制转换:

#include <iostream>
using namespace std;

int main()
{
    int x = 42;
    float* pf = reinterpret_cast<float*>(&x);
    (*pf)++;
    cout << *pf;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

你可以看出这是多么危险.事实上,我在我的机器上运行时的输出是1,绝对不是42 + 1.

  • 您的以下代码严格违反别名,因此具有未定义的行为。 (2认同)

AnT*_*AnT 41

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

你要做的不是重新解释.如果要将inta 重新解释为double必须将其转换为引用类型

double y = reinterpret_cast<double&>(x); 
Run Code Online (Sandbox Code Playgroud)

虽然等效的基于指针的重新解释可能更明确

double y = *reinterpret_cast<double*>(&x); // same as above
Run Code Online (Sandbox Code Playgroud)

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

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

所以,最终归结为你想要实现的目标.记忆重新解释?往上看.某种更有意义int,以double转换?如果是这样,reinterpret_cast在这里不会帮助你.

  • `reinterpret_cast 只能执行指针到指针转换和引用到引用转换(加上指针到整数和整数到指针的转换)` 这使问题变得扁平化,可以作为答案接受。 (4认同)

R S*_*hko 11

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

下面列出了可以使用reinterpret_cast显式执行的转换.使用reinterpret_cast不能显式执行其他转换.

并且没有列出任何描述在积分和浮点类型之间转换(或在整数类型之间转换,甚至这是非法的reinterpret_cast<long>(int(3));)


fin*_*nnw 10

如果您尝试将您的位转换int为a的表示double,则需要转换地址而不是值.您还必须确保尺寸匹配:

uint64_t x = 0x4045000000000000;
double y = *reinterpret_cast<double *>(&x);
Run Code Online (Sandbox Code Playgroud)


Dom*_*ney 5

编译器会拒绝你所写的无稽之谈,因为intdouble可能与不同大小的物体。您可以通过这种方式实现相同的效果,尽管这肯定是危险的:

int x = 0;
double y = *reinterpret_cast<double*>(&x);
Run Code Online (Sandbox Code Playgroud)

这是潜在的危险,因为如果xy是不同的大小(假设int是四个字节和double八个字节)那么当您取消引用八个字节的内存&x以填充时,y您将访问四个字节x和四个字节......无论接下来发生什么在内存中(可能是 的开始y,或垃圾,或其他完全不同的东西。)

如果要将整数转换为双精度数,请使用 astatic_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]
}
Run Code Online (Sandbox Code Playgroud)

  • 不是编译器拒绝它的原因,而是关于类型大小的讨论很有价值。 (3认同)

Dav*_*eas 5

重新解释强制转换允许您将内存块重新解释为不同的类型。这必须在指针或引用上执行:

int x = 1;
float & f = reinterpret_cast<float&>(x);
assert( static_cast<float>(x) != f );   // !!
Run Code Online (Sandbox Code Playgroud)

另一件事是,它实际上是一个非常危险的转换,不仅因为结果出现奇怪的值,或者上面的断言没有失败,而且因为如果类型的大小不同,并且您从“源”重新解释为“目标”类型,对重新解释的引用/指针的任何操作都将访问sizeof(destination)字节。如果sizeof(destination)>sizeof(source)这将超出实际的变量内存,可能会杀死您的应用程序或覆盖除源或目标之外的其他变量:

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.
assert( t.y != 20 );
Run Code Online (Sandbox Code Playgroud)