为什么将unsigned char *强制转换为char *需要reinterpret_cast?

时间:2019-04-14 23:46:50

标签: c++ c++17

stackoverflow上有许多关于读写未签名字符的文章。这些帖子建议使用reinterpret_castunsigned char*投射到char *。我想知道为什么需要它,因为两种类型的大小都相同。

我在Windows和Linux上运行下面的代码,它可以正确运行(带有或不带有重新解释演员表)。我想念什么吗?有人可以发布没有reinterpret_cast才能使用的代码吗?请注意,我在说的是unsigned char(不是unsigned int)。

#include <iostream>
#include <fstream>

std::ofstream os;
unsigned char *buff = new unsigned char[3]{ 0xe4, 0xe1, 0xd4 };
os.open("image.jpg", std::ios::out | std::ios::binary);

os.write(reinterpret_cast<char*>(buff), 3 * sizeof(unsigned char));
// or: os.write((char*)(buff), 3 * sizeof(unsigned char));
os.close();

std::ifstream file;
memset(buff, 0, 3 * sizeof(unsigned char));

file.open("image.jpg", std::ios::in | std::ios::binary);
file.read(reinterpret_cast<char*>(buff), 3 * sizeof(unsigned char));
//or: file.read((char *)buff, 3 * sizeof(unsigned char));
file.close();

2 个答案:

答案 0 :(得分:3)

reinterpret_cast从未被“需要”; reinterpret_cast可以做的任何事情都可以通过C样式转换很好地完成。

之所以存在特殊的强制转换语法,是因为需要reinterpret_cast的事物往往是危险的事物,因此应该引起注意代码中的这些要点。 reinterpret_cast还可以防止意外删除const,C风格的强制转换将使您可以删除。{p>

答案 1 :(得分:2)

  

为什么将无符号char *强制转换为char *需要reinterpret_cast?

C ++是一种类型化的语言。尽管unsigned charchar的大小不同,但它们是分开的类型。指向unsigned char的指针和指向char的指针也是单独的类型。

C ++语言具有类型安全性。类型系统旨在通过禁止将一个对象当作另一种无关类型使用来防止犯错。存在从某些类型到其他类型的隐式转换,这允许从另一种类型的对象创建一种新的对象 1 。此外,还有显式转换,当不存在隐式转换时,它们允许相同的转换。显式转换之一允许完全绕过类型系统:重新解释转换。

1 同样,您可以将引用转换为其他类型的新引用。

charunsigned char无关。指向一个的指针不能隐式转换为指向另一个的指针。当参数具有另一种类型时,将其作为参数传递是格式错误的。如果您明确告诉编译器忽略类型系统,那么它将无法保护您免受使用错误类型的潜在错误。在这种情况下,重新解释是有意的,并且(据我所知)不是错误。这些有意的重新解释是存在重新解释转换的原因。

  

我想知道为什么需要它,因为两种类型的尺寸都相同。

类型的含义并不能完全由类型的大小来描述。


请注意,重新解释转换是不安全的。处理重新解释的指针/引用时,必须遵循许多规则,违反这些规则中的任何规则都将导致未定义的行为。仅仅因为这里可能是正确的,所以不要假设每次遇到类型不匹配时都可以使用重新解释强制转换。

2 另外请注意,如果不存在符合类型系统的转换,则C样式强制转换(char*)buff会重新解释强制转换。它还将执行const强制转换,而重新解释强制转换则无效。这使得C样式转换更加不安全。通常建议显式使用您打算使用的类型转换(静态,重新解释或const转换),而不是C样式转换,后者会根据适合的情况执行这些转换之一或组合。

  

有人可以发布没有reinterpret_cast无法使用的代码吗?

如果您从程序中删除reinterpret_cast,则它将格式错误。该标准不能保证它会起作用。如果使用不扩展语言的编译器,则可能无法正常工作。例如,GCC refuses to compile

当然,由于 2 ,任何需要使用reinterpret_cast的程序都可以重写为C样式。


P.S。通常,这是一个更好的设计,可以在可能的情况下避免强制转换。在这种情况下,您可以使用std::basic_ofstream<unsigned char>std::basic_ifstream<unsigned char>,并且不需要强制转换。