代码之家  ›  专栏  ›  技术社区  ›  M.Jafar

为什么interpret_cast运算符在cpp中被认为是危险的?有更好的方法吗?

  •  0
  • M.Jafar  · 技术社区  · 3 年前

    我在研究cpp中文件的随机访问。我遇到了relpret_cast运算符。它允许您将指针从一种类型强制转换为另一种类型,即使这些类型没有任何关联。然而,它被认为是危险的,可能会产生意想不到的结果和程序崩溃。我想了解为什么以及如何做到这一点。

    我编写的代码:

    #include <iostream>
    #include <fstream>
    using namespace std;
    int main()
    {
        fstream file("example.txt", ios::out);
        if (!file)
        {
            cerr << "Failed to open file." << endl;
            return 1;
        }
        file.seekp(4 * sizeof(int), ios::beg);
        int newValue = 50;
        file.write(reinterpret_cast<const char *>(&newValue), sizeof(int));
        file.close();
        return 0;
    }
    
    0 回复  |  直到 3 年前
        1
  •  1
  •   user10    3 年前

    假设你有 unsigned int B和 signed float A.它们的尺寸一样,你可能会认为 uint32_t* B = reinterpret_cast<uint32_t*>(A) 将产生一些有意义的结果。但是 有符号浮点数 具有完全不同的比特模式,包括符号比特、指数部分和分数部分。现在你可以想象,当符号、指数和分数一起被视为一个正整数时,这种强制转换的结果将是多么的无关紧要。 reinterpret_cast 如果使用不当,是未定义行为的最佳来源之一。

        2
  •  1
  •   RawkFist    3 年前

    指针的数据类型定义了它所指向的位的含义。例如,无符号整数只使用二进制编码,即无符号4位整数1010将被解释为十进制10。但是,如果要将指针类型更改为带符号,则会读入位 Two's Complement 并被解释为小数-6。浮点类型再次具有完全不同的位表示(即。 the IEEE 754 standard 。换句话说: 指针类型定义如何解释位

    reinterpret_cast 只更改指针类型,而不更改存储的位。这意味着,由以前的数据类型给出的任何语义在转换后都会丢失,并且在强制转换之前和之后解释的值可能会大不相同。只有当您知道数据的位表示并需要对其进行操作时,才应该使用此强制转换。

    这可能不仅会在语义方面造成麻烦,还会在内存方面造成问题,因为它允许您转换到更广泛的数据类型。

    uint32_t A[1] = {1};
    uint64_t* B = reinterpret_cast<uint64_t*>(A);
    

    这是使用relpret_cast滥用内存的典型示例。你可以很容易地得到一个指向相同内存地址的指针 A 指向,但是 B 期望每个元素64位而不是32位。因此,取消引用 B 与从 A[1] :您正在尝试访问内存,这不是原始数据的一部分。