如何使用 std::string 以正确的方式存储字节(无符号字符)?
How to use std::string to store bytes (unsigned chars) in a right way?
我正在编写 LZ77 压缩算法,但我无法在字符串中存储无符号字符。为了压缩任何文件,我使用它的二进制表示,然后将其读取为 chars
(因为 1 个字符等于 1 个字节,afaik)到 std::string
。 chars
一切正常。但经过一段时间的谷歌搜索后,我了解到 char
并不总是 1 个字节,所以我决定将其换成 unsigned char
。事情开始变得棘手了:
- 当压缩普通 .txt 时,一切都按预期工作,我在解压前后得到相同的文件(我认为应该如此,因为我们基本上在字节转换前后处理文本)
- 但是,当尝试压缩 .bmp 时,解压后的文件与输入文件相比丢失了 3 个字节(我在尝试将无符号字符保存到 std::string 时丢失了这 3 个字节)
So, my question is – is there a way to properly save unsigned chars to
a string?
我尝试使用 typedef basic_string<unsigned char> ustring
并将所有相关函数交换为与 unsigned char
一起使用的基本替代函数,但我仍然丢失了 3 个字节。
UPDATE: I found out that 3 bytes (symbols) are lost not because of
std::string, but because of std::istream_iterator
(that I use instead
of std::istreambuf_iterator
) to create string of unsigned chars
(because std::istreambuf_iterator
's argument is char, not unsigned
char)
那么,这个问题有什么解决方案吗?
示例:
std::vector<char> tempbuf(std::istreambuf_iterator<char>(file), {}); // reads 112782 symbols
std::vector<char> tempbuf(std::istream_iterator<char>(file), {}); // reads 112779 symbols
示例代码:
void LZ77::readFileUnpacked(std::string& path)
{
std::ifstream file(path, std::ios::in | std::ios::binary);
if (file.is_open())
{
// Works just fine with char, but loses 3 bytes with unsigned
std::string tempstring = std::string(std::istreambuf_iterator<char>(file), {});
file.close();
}
else
throw std::ios_base::failure("Failed to open the file");
}
char
的所有形式(以及与 unsigned char
同构的 std::byte
)始终是系统支持的最小可能类型。 C++ 标准定义 sizeof(char)
及其变体应始终正好为 1.
"One"什么?那是实现定义的。但是系统中的每种类型的大小都是 sizeof(char)
的倍数。
所以您不必太担心 char
不是一个字节的系统。如果您在 CHAR_BITS
不是 8 的系统下工作,那么该系统根本无法直接处理 8 位字节。因此 unsigned char
不会是任何 different/better 用于此目的。
至于您的问题的细节,istream_iterator
与 istreambuf_iterator
迭代器根本不同。后者的目的是允许迭代器访问作为值序列的实际流。 istream_iterator<T>
的目的是允许访问流,就像通过使用 T
值执行重复的 operator >>
调用序列一样。
因此,如果您正在执行 istream_iterator<char>
,那么您就是说您想要读取流,就像您对每个迭代器访问执行 stream >> some_char;
变量一样。这实际上与直接访问流的字符不同构。具体来说,FormattedInputFunctions like operator>>
可以执行诸如跳过空格之类的操作,具体取决于您如何设置流。
istream_iterator
正在使用 operator>>
读取,它通常会跳过空格作为其功能的一部分。如果你想禁用该行为,你必须做
#include <ios>
file >> std::noskipws;
我正在编写 LZ77 压缩算法,但我无法在字符串中存储无符号字符。为了压缩任何文件,我使用它的二进制表示,然后将其读取为 chars
(因为 1 个字符等于 1 个字节,afaik)到 std::string
。 chars
一切正常。但经过一段时间的谷歌搜索后,我了解到 char
并不总是 1 个字节,所以我决定将其换成 unsigned char
。事情开始变得棘手了:
- 当压缩普通 .txt 时,一切都按预期工作,我在解压前后得到相同的文件(我认为应该如此,因为我们基本上在字节转换前后处理文本)
- 但是,当尝试压缩 .bmp 时,解压后的文件与输入文件相比丢失了 3 个字节(我在尝试将无符号字符保存到 std::string 时丢失了这 3 个字节)
So, my question is – is there a way to properly save unsigned chars to a string?
我尝试使用 typedef basic_string<unsigned char> ustring
并将所有相关函数交换为与 unsigned char
一起使用的基本替代函数,但我仍然丢失了 3 个字节。
UPDATE: I found out that 3 bytes (symbols) are lost not because of std::string, but because of
std::istream_iterator
(that I use instead ofstd::istreambuf_iterator
) to create string of unsigned chars (becausestd::istreambuf_iterator
's argument is char, not unsigned char)
那么,这个问题有什么解决方案吗?
示例:
std::vector<char> tempbuf(std::istreambuf_iterator<char>(file), {}); // reads 112782 symbols
std::vector<char> tempbuf(std::istream_iterator<char>(file), {}); // reads 112779 symbols
示例代码:
void LZ77::readFileUnpacked(std::string& path)
{
std::ifstream file(path, std::ios::in | std::ios::binary);
if (file.is_open())
{
// Works just fine with char, but loses 3 bytes with unsigned
std::string tempstring = std::string(std::istreambuf_iterator<char>(file), {});
file.close();
}
else
throw std::ios_base::failure("Failed to open the file");
}
char
的所有形式(以及与 unsigned char
同构的 std::byte
)始终是系统支持的最小可能类型。 C++ 标准定义 sizeof(char)
及其变体应始终正好为 1.
"One"什么?那是实现定义的。但是系统中的每种类型的大小都是 sizeof(char)
的倍数。
所以您不必太担心 char
不是一个字节的系统。如果您在 CHAR_BITS
不是 8 的系统下工作,那么该系统根本无法直接处理 8 位字节。因此 unsigned char
不会是任何 different/better 用于此目的。
至于您的问题的细节,istream_iterator
与 istreambuf_iterator
迭代器根本不同。后者的目的是允许迭代器访问作为值序列的实际流。 istream_iterator<T>
的目的是允许访问流,就像通过使用 T
值执行重复的 operator >>
调用序列一样。
因此,如果您正在执行 istream_iterator<char>
,那么您就是说您想要读取流,就像您对每个迭代器访问执行 stream >> some_char;
变量一样。这实际上与直接访问流的字符不同构。具体来说,FormattedInputFunctions like operator>>
可以执行诸如跳过空格之类的操作,具体取决于您如何设置流。
istream_iterator
正在使用 operator>>
读取,它通常会跳过空格作为其功能的一部分。如果你想禁用该行为,你必须做
#include <ios>
file >> std::noskipws;