为什么 std::basic_fstream<unsigned char> 不起作用?
Why std::basic_fstream<unsigned char> won't work?
尝试编译此代码时:
std::fstream file("file.name", std::ios::out | std::ios::binary);
uint8_t buf[BUFSIZE];
//Fill the buffer, etc...
file.write(buf, BUFSIZE);
编译器会警告我在调用 write()
时从 unsigned char
到 char
的非常不健康的转换。由于 std::fstream
实际上只是 std::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
使用了一些字符编码机制,并且由于为 char
定义了一个但 none 为 unsigned char
定义了一个,因此文件流在尝试使用时静默失败“错误的”字符数据类型...至少我是这样看的。
但这也是我不明白的。不需要任何字符编码。我什至不以文本模式打开文件,我想处理二进制数据。这就是为什么我使用 uint8_t
类型的数组,而不是 char,使用这种数据类型比使用普通的 char
感觉更自然。但在我决定放弃 uint8_t
数据类型并接受使用 char
缓冲区之前,或者开始使用定义为 char
的自定义 byte
数据类型数组之前,我'我想问两个问题:
- 阻止我使用无符号字符数据类型的机制到底是什么?它真的与字符编码有关,还是有其他用途?为什么文件流适用于带符号的字符数据类型,但不适用于无符号的数据类型?
- 假设我仍然想使用
std::basic_fstream<uint8_t>
,无论它多么(不)合理 - 有什么办法可以实现吗?
std::basic_fstream<unsigned char>
不起作用,因为它使用 std::char_traits<unsigned char>
,但标准库不提供这样的专业化,请参阅 std::char_traits
了解详细信息。
如果你想read/write二进制数据,你需要使用std::basic_fstream<char>
,用std::ios_base::binary
标志打开它并使用std::basic_ostream<CharT,Traits>::write
函数写入二进制数据.
这是一些遗留问题,因为所有 char
类型都可用于表示二进制数据。标准库使用 char
可能是因为这是完成这项工作的最短的输入和阅读方式。
What exactly is that mechanism that stops me from using unsigned character datatype?
没有 std::char_traits<unsigned char>
专业化。
Is it really something related to character encoding, or does it serve some other purpose?
std::char_traits
在其界面中有一些明确定义的用途,但不包括 decoding/encoding。后者由 codecvt
完成,请参阅那里的用法示例。
Why file stream works fine with signed character data types, but not for unsigned ones?
因为std::basic_ostream<CharT,Traits>::write
接受CharT
,您为流指定的第一个模板参数。它写入与读取相同的字符类型,并使用 codecvt
将 CharT
转换为字节。
Assuming that I still would want to use std::basic_fstream<uint8_t>
, regardless how (un)reasonable it is - is there any way to achieve that?
标准 class 和函数模板不能专门用于内置类型 if I am not mistaken。您需要使用 std::char_traits
接口创建另一个 class 并将其指定为标准流的第二个模板参数。我想,你需要一个非常强大的(哲学上的)理由才能卷起袖子去做。
如果不这样做,您可能想继续使用 std::fstream<char>
并执行 stream.write(reinterpret_cast<char const*>(buf), sizeof buf);
。
其实char
和uint8_t
可以是不同的类型。这也意味着它们可以有不同的 std::char_traits
。字符特征类型是 std::basic_fstream
的第二个模板参数,默认情况下是 std::char_traits
用字符类型实例化的。 std::basic_fstream
默认通过字符特征模板参数格式化 I/O。它不简单地重定向原始字节不变。这可能就是您得到不同结果的原因。
尝试编译此代码时:
std::fstream file("file.name", std::ios::out | std::ios::binary);
uint8_t buf[BUFSIZE];
//Fill the buffer, etc...
file.write(buf, BUFSIZE);
编译器会警告我在调用 write()
时从 unsigned char
到 char
的非常不健康的转换。由于 std::fstream
实际上只是 std::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
使用了一些字符编码机制,并且由于为 char
定义了一个但 none 为 unsigned char
定义了一个,因此文件流在尝试使用时静默失败“错误的”字符数据类型...至少我是这样看的。
但这也是我不明白的。不需要任何字符编码。我什至不以文本模式打开文件,我想处理二进制数据。这就是为什么我使用 uint8_t
类型的数组,而不是 char,使用这种数据类型比使用普通的 char
感觉更自然。但在我决定放弃 uint8_t
数据类型并接受使用 char
缓冲区之前,或者开始使用定义为 char
的自定义 byte
数据类型数组之前,我'我想问两个问题:
- 阻止我使用无符号字符数据类型的机制到底是什么?它真的与字符编码有关,还是有其他用途?为什么文件流适用于带符号的字符数据类型,但不适用于无符号的数据类型?
- 假设我仍然想使用
std::basic_fstream<uint8_t>
,无论它多么(不)合理 - 有什么办法可以实现吗?
std::basic_fstream<unsigned char>
不起作用,因为它使用 std::char_traits<unsigned char>
,但标准库不提供这样的专业化,请参阅 std::char_traits
了解详细信息。
如果你想read/write二进制数据,你需要使用std::basic_fstream<char>
,用std::ios_base::binary
标志打开它并使用std::basic_ostream<CharT,Traits>::write
函数写入二进制数据.
这是一些遗留问题,因为所有 char
类型都可用于表示二进制数据。标准库使用 char
可能是因为这是完成这项工作的最短的输入和阅读方式。
What exactly is that mechanism that stops me from using unsigned character datatype?
没有 std::char_traits<unsigned char>
专业化。
Is it really something related to character encoding, or does it serve some other purpose?
std::char_traits
在其界面中有一些明确定义的用途,但不包括 decoding/encoding。后者由 codecvt
完成,请参阅那里的用法示例。
Why file stream works fine with signed character data types, but not for unsigned ones?
因为std::basic_ostream<CharT,Traits>::write
接受CharT
,您为流指定的第一个模板参数。它写入与读取相同的字符类型,并使用 codecvt
将 CharT
转换为字节。
Assuming that I still would want to use
std::basic_fstream<uint8_t>
, regardless how (un)reasonable it is - is there any way to achieve that?
标准 class 和函数模板不能专门用于内置类型 if I am not mistaken。您需要使用 std::char_traits
接口创建另一个 class 并将其指定为标准流的第二个模板参数。我想,你需要一个非常强大的(哲学上的)理由才能卷起袖子去做。
如果不这样做,您可能想继续使用 std::fstream<char>
并执行 stream.write(reinterpret_cast<char const*>(buf), sizeof buf);
。
其实char
和uint8_t
可以是不同的类型。这也意味着它们可以有不同的 std::char_traits
。字符特征类型是 std::basic_fstream
的第二个模板参数,默认情况下是 std::char_traits
用字符类型实例化的。 std::basic_fstream
默认通过字符特征模板参数格式化 I/O。它不简单地重定向原始字节不变。这可能就是您得到不同结果的原因。