Как я могу прочитать 0xFF в файле с libc ++ istream_iterator?

Рассмотрим следующий пример кода:

#include <iostream>

using namespace std;

int main()
{
istreambuf_iterator<char> eos;
istreambuf_iterator<char> iit(cin.rdbuf());
int i;
for (i = 0; iit != eos; ++i, ++iit) {
cout << *iit;
}
cout << endl << i << endl;
}

И входной файл, содержащий следующее: «foo \ xffbar»:

$ hexdump testin
0000000 66 6f 6f ff 62 61 72
0000007

Теперь для теста с использованием clang libc ++ vs gnu libstdc ++:

$ make test
clang++ -std=c++11 -stdlib=libc++ -Wall -stdlib=libc++ -o bug-libcc bug.cpp
clang++ -std=c++11 -stdlib=libc++ -Wall -stdlib=libstdc++ -o bug-libstd bug.cpp
./bug-libcc < testin
foo
3
./bug-libstd < testin
foo�bar
7

Как видите, версия libc ++ считает, что 0xff — это конец потока, и он прекращает чтение. Так что это приводит к паре вопросов.

1) Это ошибка в libc ++, о которой я должен сообщить? Мой поиск в Google для существующих ошибок ничего не обнаружил.

2) Есть ли хороший способ обойти эту проблему?

РЕДАКТИРОВАТЬ

Следующий код работает:

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
ifstream ifs ("testin", ios::binary);
istreambuf_iterator<char> eos;
istreambuf_iterator<char> iit(ifs.rdbuf());
int i;
for (i = 0; iit != eos; ++i, ++iit) {
cout << *iit;
}
cout << endl << i << endl;
}

Приводит меня к мысли, что это проблема двоичного преобразования, но это не объясняет, почему libstdc ++ работает должным образом.

EDIT2

Использование файла без двоичного кода также работает нормально:

ifstream ifs ("testin");

Так что определенно происходит что-то подозрительное. Похоже, что это может быть проблемой при реализации cin, а не итератора.

5

Решение

К сожалению, в libc ++ все еще есть ошибка (в дополнение к одному указанному ecatmur). Вот исправление:

Index: include/__std_stream
===================================================================
--- include/__std_stream    (revision 176092)
+++ include/__std_stream    (working copy)
@@ -150,7 +150,7 @@
{
for (int __i = __nread; __i > 0;)
{
-            if (ungetc(__extbuf[--__i], __file_) == EOF)
+            if (ungetc(traits_type::to_int_type(__extbuf[--__i]), __file_) == EOF)
return traits_type::eof();
}
}

Я проверю это как можно скорее. Извините за ошибку. Спасибо, что обратили на это мое внимание.

Исправлена ​​фиксация ревизии 176822 в публичной svn-магистрали libcxx. Исправление требует перекомпилированного dylib, даже если исправление находится в заголовке.

5

Другие решения

Я думаю, что вы могли найти ошибку, которая уже была исправлена. Этот коммит (от @ Говард Хиннант) содержит следующие изменения:

@@ -104,7 +104,7 @@
int __nread = _VSTD::max(1, __encoding_);
for (int __i = 0; __i < __nread; ++__i)
{
-        char __c = getc(__file_);
+        int __c = getc(__file_);
if (__c == EOF)
return traits_type::eof();
__extbuf[__i] = static_cast<char>(__c);
@@ -131,7 +131,7 @@
if (__nread == sizeof(__extbuf))
return traits_type::eof();
{
-                    char __c = getc(__file_);
+                    int __c = getc(__file_);
if (__c == EOF)
return traits_type::eof();
__extbuf[__nread] = static_cast<char>(__c);

Вы заметите, что старая версия хранила возвращаемое значение getc в char, который является нет-нет по точной причине, что это смущает char значение 0xff с int значение EOF (Т.е. -1).

Ошибка распространяется только на cin потому что затронутые методы включены __stdinbuf, который использует libc ++ для реализации cin только; ifstream например использования basic_filebuf<char>,

Проверить libcxx/include/__std_stream файл в вашей системе, чтобы увидеть, есть ли у него эта ошибка; если это так, примените патч, и он должен это исправить.

2

Итератор извлекает из потока.
Поток должен быть открыт с binary режим для предотвращения любых переводов на исходные данные.

Далее не используйте char, char Тип может быть подписан, без знака или нет, в зависимости от компилятора. Я рекомендую использовать uint8_t при чтении двоичных октетов.

Попробуйте что-то вроде этого:

#include <cstdint>
using std::uint8_t;
istreambuf_iterator<uint8_t> eos;
1
По вопросам рекламы [email protected]