代码之家  ›  专栏  ›  技术社区  ›  Vlad the Impala

为什么不重新解释编译?

  •  55
  • Vlad the Impala  · 技术社区  · 16 年前

    我明白 reinterpret_cast 很危险,我只是为了测试它。我有以下代码:

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

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

    从类型“float”到类型“double”的转换无效

    发生什么事?我想 重新解释铸模 你能用这个流氓演员表把苹果变成潜艇吗?为什么这个简单的演员表不能编译?

    10 回复  |  直到 7 年前
        1
  •  41
  •   John Dibling    16 年前

    通过将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;
    }
    

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

    如果你真的想假装 X 是浮球,那么你真的想投 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。

        2
  •  38
  •   AnT stands with Russia    10 年前

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

    你要做的不是重新解释。如果你想重新解释 int 作为一个 double 您必须将其转换为引用类型

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

    尽管等价的基于指针的重新解释可能更为明确

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

    尽管如此,请注意, 重新解释铸模 可以转换引用/指针类型,实际尝试通过结果引用/指针读取数据会产生未定义的行为。

    当然,在任何情况下,在平台上 int 双重的 不同尺寸的(因为在较大的情况下 双重的 你会读到超出记忆的 x )。

    所以,归根结底,一切都归结为你试图达到的目标。记忆重新解释?见上文。某种更有意义的 int 双重的 转换?如果是这样, 重新解释铸模 在这里帮不了你。

        3
  •  11
  •   R Samuel Klatchko    16 年前

    reinterpret_cast不是通用的cast。根据C++ 03规范部分5.2.101:

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

    并且没有列出描述整型和浮点型(或整型之间)转换的内容,即使这是非法的 reinterpret_cast<long>(int(3)); )

        4
  •  9
  •   finnw    16 年前

    如果你想转换你的 int 表示 double ,你需要铸造 地址 不是值。您还必须确保尺寸匹配:

    uint64_t x = 0x4045000000000000;
    double y = *reinterpret_cast<double *>(&x);
    
        5
  •  3
  •   Dominic Cooney    16 年前

    编译器拒绝了你写的废话,因为 int double 可能是不同尺寸的物体。你可以通过这种方式达到同样的效果,尽管这确实很危险:

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

    这是潜在的危险,因为如果 x y 大小不同吗(比如 int 是四个字节 双重的 是8字节),然后当您在 &x 填写 Y 您将访问 X 四个字节的…记忆中接下来发生的一切(可能是 Y 或者垃圾,或者其他的东西。)

    如果要将整数转换为双精度数,请使用 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]
    }
    
        6
  •  2
  •   David Rodríguez - dribeas    16 年前

    reinterpret cast允许您将内存块重新解释为不同的类型。必须在指针上执行此操作 或参考文献 :

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

    另一件事是,它实际上是一个非常危险的强制转换,不仅因为结果中出现了奇怪的值,或者上面的断言没有失败,而且因为如果类型的大小不同,并且您从“源”类型重新解释为“目标”类型,则重新解释的引用/指针上的任何操作都将访问 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.
    asswet( t.y != 20 );
    
        7
  •  1
  •   Alex B    16 年前

    reinterpret_cast 最好用于指针。所以指向一个物体的指针可以变成“潜水艇”。

    msdn :

    Reinterpret-Cast运算符可以是 用于char*到等转换 int*或一个\u class*to 不相关的_类*,其本质是 不安全的。

    重新解释的结果 不能安全地用于任何事情 除了被抛回 原始类型。其他用途是 最好,不重要。

        8
  •  0
  •   Matt Davis    16 年前

    将int值强制转换为double值并不需要强制转换。编译器将隐式执行赋值。

    reinterpret_cast与指针和引用一起使用,例如, int * 到A double * .

        9
  •  0
  •   Andy White    16 年前

    这很有趣。可能它在尝试将强制转换为double之前正在进行从int到float的隐式转换。int和float类型通常以字节为单位具有相同的大小(当然,这取决于您的系统)。

        10
  •  0
  •   Evan Moran    7 年前

    这种重新解释的方法让我走上了一条奇怪的道路,结果千差万别。最后,我发现这样的记忆力要好得多!

    double source = 0.0;
    uint64_t dest;
    memcpy(&dest, &source, sizeof(dest));