Я кодирую алгоритм сжатия LZ77, и у меня возникают проблемы с сохранением беззнаковых символов в строке. Чтобы сжать любой файл, я использую его двоичное представление, а затем читаю его как chars
(поскольку 1 символ равен 1 байту, афаик) в std::string
. С chars
все отлично работает. Но после некоторого времени гугления я узнал, что char
не всегда 1 байт, поэтому решил поменять его на unsigned char
. И тут начинаются сложности:
- При сжатии простого .txt все работает как положено, я получаю одинаковые файлы до и после распаковки (я предполагаю, что так и должно быть, потому что мы в основном работаем с текстом до и после преобразования байтов)
- Однако при попытке сжать .bmp распакованный файл теряет 3 байта по сравнению с входным файлом (я теряю эти 3 байта при попытке сохранить неподписанные символы в std::string)
Итак, мой вопрос: есть ли способ правильно сохранить беззнаковые символы в строку?
Я пытался использовать typedef basic_string<unsigned char> ustring
и поменять все связанные функции на их основные альтернативы для использования с unsigned char
, но все равно теряю 3 байта.
ОБНОВЛЕНИЕ: я обнаружил, что 3 байта (символа) теряются не из-за std::string, а из-за
std::istream_iterator
(который я использую вместоstd::istreambuf_iterator
) для создания строки беззнаковых символов (потому что аргументstd::istreambuf_iterator
это char, а не 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
не 1 байт? - person Eljay   schedule 30.11.2019std::vector<std::byte>
для хранения байтовых данных. Если вы хотите избежать переписывания такого большого количества кода, тогдаstd::basic_string<std::byte>
(возможно, вам также придется предоставить свои собственные черты). - person Eljay   schedule 30.11.2019std::byte
не обеспечивает достаточного интерфейса (также я читал, чтоstd::byte
— это замаскированныйunsigned char
) - person asymmetriq   schedule 30.11.2019std::string
- во многих местах предполагается, что строки заканчиваются нулем, а это не то, что вам нужно. Используйтеstd::vector
. Не нужно беспокоиться о том, чтоchar
не является 8-битным. Такие системы редки, и наверняка на них не будет работать что-то еще, кроме кода вашего маленького архива. - person ALX23z   schedule 30.11.2019std::vector<std::byte>>
. Сделанный. Обсуждение окончено. - person Jesper Juhl   schedule 30.11.2019char
имеет размер в один байт (чтоsizeof(char)
всегда возвращает 1). Чего он не говорит, так это того, насколько велик байт. И да, есть платформы (хоть и редкие в наше время), где размер байта не 8 бит. См.CHAR_BIT
фактический размер для данной платформы. - person Remy Lebeau   schedule 30.11.2019