为什么C风格的转换可以工作,但reinterpret_cast不能工作?

13

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

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

5
使用static_cast代替,应该能正常工作。 - Neel Basu
@BoPersson:我不会认为每个使用C样式转换的人都是错误的。从unsigned charint的转换是完全定义良好的。 - Ed S.
6个回答

22
(通俗易懂的说)reinterpret_cast 用于以实现定义的方式将一个对象的位解释为另一种类型。你不想这样做:你想进行转换(从 char 到 int)。请使用 static_cast
(所有可能使用 reinterpret_cast 的情况都列在 5.2.10 中;这不是其中之一。)

2
此外,所有使用 reinterpret_cast 的地方都涉及指针或引用类型(以及那些无用的同类型转换)。 - Xeo

15
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<int>

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

6
  • reinterpret_cast :"...允许任何整数类型转换为任何指针类型,反之亦然。" 仅在需要将某些东西转换为正确的指针类型时使用它(例如,在除了8位系统以外的任何情况下,无符号字符明显不能成为指针)。

  • static_cast:当您想要将一种类型转换为另一种类型时使用此方法(例如,将float转换为int或unsigned char转换为int)。

cout 尝试将无符号字符打印为ASCII字符代码,因此通过 static_cast<int>(v[0]) 转换为int是正确的做法。


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

3

reinterpret_cast 可以将指针类型的值转换为其他指针类型的值或整数值,反之亦然,以允许对目标指针值进行解引用。但是您试图将一个整数类型的值转换为另一个整数类型的值。这是行不通的。reinterpret_cast 支持引用类型的转换,这相当于后续跟随解引用的相应指针值转换。因此,您似乎想要执行以下操作:

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

这是格式正确的,但将无符号字符重新解释为整数对象,这不能保证有效(可能出现的问题范围从存储的无效对齐到不兼容的大小-1字节与4字节)。您可以通过进行 (int)v[0] 强制转换来解决这些情况,我认为这是完全可以的。您也可以使用 +v[0],它会自动将值提升为(有符号或无符号)int


0

static_cast将像其他人所指出的那样执行正确的操作。它比C风格的转换要弱,因此不太可能造成损害并导致未定义的行为。

reinterpret_cast也比C风格的转换要弱,但它并不严格比static_cast更强大;static_cast可以做到的事情,reinterpret_cast不能。您已经遇到其中之一。

reinterpret_cast旨在允许您将一个类型的值存储为另一个类型的值,然后再返回原始类型。您可以使用此方法在兼容的整数和指针类型之间进行转换。您可以使用此方法在指针类型之间进行转换,然后再进行转换。

通常而言,reinterpret_cast将您转换为“保持”值,该保持值最好是实现定义的,而经常使用它是未定义的行为。

因此,除非您确实需要这样做,否则请避免使用它。

char转换为int通常不是重新解释的问题。

static_cast<int>(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;

你会得到非常类似于调用一个带有 char 参数的 int 函数的行为,我相信这正是你想要的。


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

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

char* 也是如此;它们被视为指向以 null 结尾的缓冲区的指针,例如 "hello world",而不是像其他指针一样。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接