1

尝试编译此代码时:

std::fstream file("file.name", std::ios::out | std::ios::binary);
uint8_t buf[BUFSIZE];
//Fill the buffer, etc...
file.write(buf, BUFSIZE);

编译器会警告我从调用到unsigned char的oh-not-so-healthy 转换到. 事实上,它只是一个 typedef ,人们可能会认为使用而不是允许他们在没有警告的情况下编译上面的代码,正如预期的模板类型指针一样。charwrite()std::fstreamstd::basic_fstream<char>std::basic_fstream<uint8_t>write()

这当然可行,但又出现了另一个问题。即使这段代码编译得很好:

std::basic_fstream<uint8_t> file("file.name", std::ios::out | std::ios::binary);
uint8_t buf[BUFSIZE];
//Fill the buffer, etc...
file.write(buf, BUFSIZE);

write()即使以前的版本正在运行,它现在也会在调用 时失败(忽略编译器警告)。我花了一段时间来确定标准 C++ 库代码中异常是从哪里引发的,但我仍然不太明白这里的情况。它看起来std::basic_fstream使用了一些字符编码机制,并且由于定义了一个 forchar但没有定义 for unsigned char,因此文件流在尝试使用“错误”字符数据类型时会默默地失败......至少我是这么看的。

但这也是我不明白的。不需要任何字符编码。我什至不以文本模式打开文件,我想处理二进制数据。这就是为什么我使用类型数组而uint8_t不是 char 的原因,使用这种数据类型而不是普通的 old 感觉更自然char。但在我决定放弃uint8_t数据类型并接受使用char缓冲区或开始使用byte定义为 的自定义数据类型的数组之前char,我想问两个问题:

  1. 究竟是什么机制阻止我使用无符号字符数据类型?它真的与字符编码有关,还是有其他用途?为什么文件流适用于有符号字符数据类型,但不适用于无符号数据类型?
  2. 假设我仍然想使用std::basic_fstream<uint8_t>,无论它多么(不)合理 - 有没有办法实现这一点?
4

2 回答 2

4

std::basic_fstream<unsigned char>不起作用,因为它使用std::char_traits<unsigned char>但标准库不提供这样的专业化,请参阅std::char_traits完整详细信息。

如果你想读/写二进制数据,你需要使用,用标志std::basic_fstream<char>打开它并使用函数来写入二进制数据。std::ios_base::binarystd::basic_ostream<CharT,Traits>::write

这是一个遗留问题,因为所有char类型都可以用来表示二进制数据。使用标准库char可能是因为它是完成这项工作的最短的键入和阅读库。


究竟是什么机制阻止我使用无符号字符数据类型?

没有std::char_traits<unsigned char>专业。

它真的与字符编码有关,还是有其他用途?

std::char_traits在其接口中准确定义了一些用途,但不包括解码/编码。后者由 完成codecvt,请参见那里的用法示例。

为什么文件流适用于有符号字符数据类型,但不适用于无符号数据类型?

因为std::basic_ostream<CharT,Traits>::writeaccept CharT,您为流指定的第一个模板参数。它写入它读取的相同字符类型,并使用它codecvt来转换CharT为字节。

假设我仍然想使用std::basic_fstream<uint8_t>,无论它多么(不)合理 - 有没有办法实现这一点?

如果我没记错的话,标准类和函数模板不能专门用于内置类型。您需要创建另一个具有std::char_traits接口的类,并将其指定为标准流的第二个模板参数。我想,你需要一个非常强大(哲学)的理由来卷起袖子去做。

如果你不这样做,你可能想继续使用std::fstream<char>并做stream.write(reinterpret_cast<char const*>(buf), sizeof buf);.

于 2020-11-17T22:53:14.223 回答
0

实际上charuint8_t可以是不同的类型。这也意味着他们可以有不同的std::char_traits。字符特征类型是 的第二个模板参数std::basic_fstream,默认情况下std::char_traits使用字符类型实例化。std::basic_fstream默认情况下通过字符特征模板参数格式化 I/O。它不会简单地重定向原始字节不变。这可能就是您得到不同结果的原因。

于 2020-11-17T22:53:43.960 回答