【问题标题】:Why does C style cast work but reinterpret_cast doesn't?为什么 C 风格的演员表可以工作,但 reinterpret_cast 不能?
【发布时间】:2012-08-14 19:40:16
【问题描述】:

所以我有一个两个字符数组

unsigned char v[2];

我想将 v[0] 的值显示为 0 到 255 之间的数字,但是

cout << v[0] << endl; //prints some garbage

cout << (void*)v[0] << endl; //prints the right thing but in hex

所以我尝试了

cout << (int)v[0] << endl;

printf("%d\n", v[0]);

这正是我想要的,但我一点也不喜欢。另外我完全不明白为什么这不起作用:

cout << reinterpret_cast<int>(v[0]) << endl; //compiler error

【问题讨论】:

  • 使用 static_cast 代替它应该可以工作
  • @BoPersson:我不会假设每个使用 C 风格转换的人都在错误地这样做。从unsigned charint 的演员阵容定义完美。

标签: c++ c casting reinterpret-cast


【解决方案1】:

(通俗地说)reinterpret_cast 用于以实现定义的方式将对象的位解释为另一种类型。您不希望这样:您想要转换(从 char 到 int)。请改用static_cast

reinterpret_cast 的所有可能用途都列在5.2.10 中;这不是其中之一。)

【讨论】:

  • 此外,reinterpret_cast 的所有使用都涉及指针或引用类型(以及无用的相同类型转换)。
【解决方案2】:

static_cast 正如其他人所指出的,会做正确的事。它比 C 风格的强制转换弱,因此不太可能造成破坏并导致未定义的行为。

reinterpret_cast 也弱于 C 风格的强制转换,但它严格地强于 static_cast;有些事情static_cast 可以做到reinterpret_cast 不能。您遇到了其中之一。

reinterpret_cast 旨在允许您获取一种类型的值,将它们存储为另一种类型的值,然后取回原始类型。您可以这样做来转换兼容的整数和指针类型。您可以使用它从一种指针类型转换为另一种指针类型然后再转换回来。

一般来说,reinterpret_cast 会将您的值转换为“持有”值,并且持有值最多是实现定义,并且经常使用它是未定义的行为。

所以你要避免使用它,除非你真的是认真的。

char 转换为int 通常不需要重新解释。

static_cast&lt;int&gt;(some_char) 会将char 升级为int 并为您提供适当的值。


但是,在某些情况下,我发现static_cast 太强大了。它可以进行不安全的指针转换,并算作显式转换。

这两者都可以掩盖错误。

你可以写一个严格较弱的演员表如下:

template<class T, class U>
T implicit_cast( U&& u ) { return std::forward<U>(u); }

现在可以

std::cout << implicit_cast<int>(v[0]) << std::endl;

你得到的行为非常类似于调用带有 intchar 参数的函数,我相信这就是你想要的。


这里出了什么问题?嗯,std::cout 是一个流,流注意传递的类型。 char 类型被打印为 `'a` 样式字符,而不是小整数。

为了将char 视为一个小整数,您必须将其转换为另一种整数类型。

char*也是如此;它们被视为指向char 的空终止缓冲区的指针,如"hello world",而不像其他指针。

【讨论】:

    【解决方案3】:

    reinterpret_cast 将指针类型的值转换为其他指针类型值或整数值,反之亦然,以允许取消引用目标指针值。但是,您尝试将一种整数类型值转换为另一种整数类型值。那是行不通的。 reinterpret_cast 支持引用类型的转换,这相当于使用后续取消引用转换的相应指针值。所以看来你想做

    // NOTE: THIS IS UNDEFINED BEHAVIOR
    cout << reinterpret_cast<int&>(v[0]) << endl; 
    

    这是格式正确的,但将 unsigned char 重新解释为整数对象,这不能保证工作(可能的问题范围从存储的无效对齐到不兼容的大小 - 1 字节与 4 字节)。你可以通过(int)v[0] 演员来解决这些情况,我认为这很好。您也可以说+v[0],它会自动将值提升为(有符号或无符号)int

    【讨论】:

      【解决方案4】:
      • reinterpret_cast : "...允许转换任何整数类型 转换为任何指针类型,反之亦然。”仅用于转换 可能是指向正确指针类型的指针(一个 unsigned char 显然不能是除 an 之外的任何指针 8 位系统)。

      • static_cast :当你想将一个类型转换成另一个类型时使用这个 类型(如浮点到 int,或 unsigned char 到 int)。

      cout 尝试将 unsigned char 打印为 ASCII 字符代码,因此通过 static_cast&lt;int&gt;(v[0]) 转换为 int 是正确的做法。

      【讨论】:

        【解决方案5】:
        cout << v[0] << endl; // prints some garbage
        

        不是垃圾,而是v[0]中的值所代表的字符。

        cout << (void*)v[0] << endl;
        

        这会将v[0] 中的值“转换”为指针(未定义的行为,因为它不是以开头的指针),并将该指针的值打印为十六进制值。

        cout << (int)v[0] << endl;
        

        这会将 v[0] 中的值转换为 int(定义明确;只需提升为 int)并显示该值。

        reinterpret_cast,正如其他人所提到的,对它可以做什么有一些限制。正确答案是使用static_cast&lt;int&gt;

        cout << static_cast<int>(v[0]) << endl;
        

        【讨论】:

          【解决方案6】:

          您使用 reinterpret_cast 的方式是尝试将 char 读取为 int,并且它们的大小不同。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-03-25
            • 1970-01-01
            • 2020-05-31
            • 1970-01-01
            • 2011-04-04
            • 1970-01-01
            相关资源
            最近更新 更多