2009-12-05 2 views
1

Название довольно объяснительно.C++ может содержать символ родного типа End of File?

char c = std::cin.peek(); // sets c equal to character in stream 

Я просто понял, что, возможно, родной тип char не может удерживать EOF.

спасибо, ЯМР-

+0

Можете ли вы разместить больше своего цикла после редактирования? Тестирование флага eof обычно не является лучшим способом кодирования входного цикла. Обычно лучше проверить возвращаемое значение 'peek()' (или, что еще более обычно, 'get()'?), Поскольку многие люди ошибаются, полагая, что 'eof()' вернет true, когда следующее чтение будет будет терпеть неудачу. Это также означает, что вы не обнаружите никакой другой ошибки, кроме конца файла, и можете бесконечно зацикливаться на фиктивных данных. –

+0

Вы хорошо на фронте eof, потому что вы «заглядываете» перед циклом и в самом конце цикла, но у вас все еще есть проблемы с любой ошибкой, отличной от eof. Я все еще думаю, что это проще и позволяет избежать дублирования, если вы просто проверяете возвращаемое значение 'get()' в условии while. Использование 'get()' означает, что вам не нужно «игнорировать», и вы можете просто передать прочитанный символ прямо в «расширяемый массив символов». Также для максимальной переносимости вы должны сделать 'ch = std :: istream :: traits_type :: to_char_type (cin.get());' вместо неявного преобразования в char, хотя это будет работать большую часть времени. –

ответ

8

Короткий ответ: Нет Использование INT вместо полукокса.

Слегка развернутый ответ: Нет, если вы можете получить либо символ или значение EOF из функции, такие как C-х GetChar и C++ 's заглядывать, очевидно, нормальный символ переменная не будет достаточно, чтобы удерживать оба действительных символа и значение EOF.

Даже более длинный ответ: это зависит, но он никогда не будет работать, как вы могли бы надеяться.

C и C++ имеет три типа символов (для «широких» типов, за исключением): полукокса, подписали символ и неподписанные символ. Обычный char может быть подписан или без знака, и это зависит от компиляторов.

Значение EOF является отрицательным числом, как правило, -1, так ясно, вы не можете сохранить его в неподписанного символа или в простом полукокса, который без знака. Предполагая, что ваша система использует 8-битные символы (что почти все делает), EOF будет преобразован в (десятичный) 255, и ваша программа не будет работать.

Но если ваш символа типа подпись, или если вы используете подписанного символьного типа, то да, вы можете хранить -1 в нем, так что да, он может содержать EOF. Но что происходит тогда, когда вы читаете символ с кодом 255 из файла? Он будет интерпретироваться как -1, то есть EOF (при условии, что ваша реализация использует -1). Таким образом, ваш код перестанет читать не только в конце файла, но и сразу, как только он найдет 255 символов.

+0

@ Томас: хороший ответ! – RageZ

+0

Зависит, если вы открываете файл как чтение как файл ascii или двоичный файл. Хотя из памяти мне никогда не приходилось открывать файл как ASCII всегда как двоичный. Это устраняет все проблемы с EOF и то, что люди определяют как EOF. Хотя мой отказ от EOF заключается не в том, когда документ ASCII объявляет EOF, но когда вы дойдете до конца размера файла. – Chad

+0

@ Chad: Я думаю, вы думаете о чем-то другом здесь. Если вы открываете файл в виде текста или как двоичный код не меняет, как значение EOF хранится в переменной char. –

4

Обратите внимание, что возвращаемое значение std::cin.peek() фактически типа std::basic_ios<char>::int_type, который является таким же, как std::char_traits<char>::int_type, который является int и не char.

Более важным, чем значение, возвращаемое в этом int не обязательно является простой бросок из char к int, но является результатом вызова std::char_traits<char>::to_int_type на следующий символ в потоке или std::char_traits<char>::eof() (который определен, чтобы быть EOF), если нет персонажа.

Как правило, это все реализовано точно так же, как fgetc отбрасывает символ в unsigned char, а затем к int для возвращаемого значения, так что вы можете выделить все допустимые значения символов из EOF.

Если сохранить возвращаемое значение std::cin.peek() в char то есть Possiblity, что чтение символа с положительным значением (скажем ÿ в ISO-8859-1 закодированный файл) будет сравнивать равно EOF.

Педантичность вещь будет.

typedef std::istream::traits_type traits_type; 

traits_type::int_type ch; 
traits_type::char_type c; 

while (!traits_type::eq_int_type((ch = std::cin.peek()), traits_type::eof())) 
{ 
    c = traits_type::to_char_type(ch); 
    // ... 
} 

Это, вероятно, будет больше обычного:

int ch; 
char c; 

while ((ch = std::cin.peek()) != EOF) 
{ 
    c = std::iostream::traits_type::to_char_type(ch); 
    // ... 
} 

Обратите внимание, что очень важно правильно преобразовать значение символа. Если вы выполните сравнение следующим образом: if (ch == '\xff') ..., где ch - это int, как указано выше, вы можете не получить правильные результаты. Вы должны использовать std::char_traits<char>::to_char_type на ch или std::char_traits<char>::to_int_type на константу символа, чтобы получить согласованный результат. (Однако вы, как правило, в безопасности с членами базового набора символов.)

+0

Я оценил этот ответ, но он был немного более подробным, чем я искал и несколько смутил меня. – ihtkwot

+0

Можете ли вы указать на биты, которые могут быть полезны, или вещи, которые я могу прояснить? Цель SO заключается в том, чтобы коллаборативно добраться до «лучших» ответов, поэтому любая помощь в улучшении оценивается. –

+0

Я не стану сомневаться в ясности высказываний, которые я более упомянул о моем собственном незнании языка. Я действительно просто недостаточно хорошо знаком с C++ до того момента, когда вы сразу же нажмете на меня. Думаю, в начале моего вопроса я должен был уточнить, что меня не интересует переносимость. – ihtkwot