C ++ может содержать тип нативного типа символ конца файла? - PullRequest
1 голос
/ 05 декабря 2009

Название довольно понятно.

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

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

спасибо, мр

Ответы [ 2 ]

8 голосов
/ 05 декабря 2009

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

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

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

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

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

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

4 голосов
/ 05 декабря 2009

Обратите внимание, что возвращаемое значение 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, то есть вероятность, что чтение символа с положительным значением (скажем, ÿ в кодированном файле 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 на символьной константе, чтобы получить согласованный результат. (Тем не менее, вы обычно в безопасности с членами основного набора символов.)

...