#include <stdio.h>
int main()
{
int c = getchar();
while (c != EOF) {
putchar(c);
c = getchar();
}
return 0;
}
Проблема заключается в том, чтобы отличить конец ввода от действительных данных. решение состоит в том, что getchar возвращает отличительное значение, когда нет больше ввода, значение, которое нельзя спутать ни с одним реальным символом. Это значение называется EOF, что означает «конец файла». Мы должны объявить c равным тип, достаточно большой, чтобы содержать любое значение, которое возвращает getchar. мы не можем использовать char, так как c должен быть достаточно большим, чтобы содержать EOF в дополнение к любому возможный чар. Поэтому мы используем внутр.
Из книги «Язык программирования Си». У меня есть три вопроса.
Во-первых, почему я получаю вывод ^\Quit (core dumped), когда одновременно нажимаю клавиши ctrl и 4 во время выполнения вышеуказанной программы? Я использую машину GNU/Linux.
Во-вторых, я написал такую программу:
#include <stdio.h>
int main()
{
printf("The part before EOF\n");
putchar(EOF);
printf("The part after EOF\n");
}
Затем скомпилировал это как «eof.out» и изменил int c = getchar(); в программе из книги на char c = getchar();, сохранил его, а затем скомпилировал программу как «copy.out».
Когда я запускаю команду ./eof.out | ./copy.out в терминале, я получаю вывод:
The part before EOF
Это означает, что программа «copy.out» работала правильно, так как она не напечатала второй printf, но приведенный выше отрывок из книги указывает на то, что должен был произойти какой-то сбой, так как я изменил int на char, так что же произошло?
В-третьих, когда я меняю char c = getchar(); на double c = getchar(); и запускаю команду ./eof.out | ./copy.out, я получаю следующий вывод:
The part before EOF
�The part after EOF
Почему putchar(EOF); не остановил copy.out ? Разве у double не больше байтов, чем у int и char? что происходит?
putchar(EOF) записывает один байт, который (почти наверняка, но может варьироваться в зависимости от платформы) 0xff. getchar считывает этот байт как целое число 255, и double y = getchar(), таким образом, присваивает значение 255 переменной y. Но 255 != EOF.
Относительно «отрывок из книги выше указывает на то, что должен был быть какой-то сбой, так как я изменил int на char»: отрывок из книги не говорит, что должен быть какой-то сбой. В нем говорится, что EOF — это «значение, которое нельзя спутать ни с одним реальным символом»; это не говорит, что вы не можете преобразовать EOF в char. Если ваша реализация C использует беззнаковый тип char, преобразование переносит значение по модулю 2^N, где N — количество битов в char, обычно восемь, поэтому по модулю 256. Например, -1 отображается в 255…
… Если ваша реализация C использует знаковый char, преобразование определяется реализацией.
Диапазон кодовых точек ASCII 0..127. На большинстве (всех?) платформах char может содержать значения -128..127. На большинстве (всех?) платформах EOF определяется как -1. Итак, char будет отлично работать в вашей программе.
@EricPostpischil, книга технически неверна, если вы вырвете ее утверждение из контекста или интерпретируете «не может» как исключающее ошибку программиста. Но когда это утверждение понимается как утверждение о поведении getchar(), оно абсолютно правильно. При вызове, когда на самом деле есть символ, который можно вернуть, getchar() / getc() / fgetc() возвращает этот символ как unsigned char (преобразованный в int), тогда как EOF гарантированно расширяется до отрицательного целого числа. Первое всегда отличимо от второго.
Ваши три вопроса на самом деле не связаны друг с другом, поэтому они, вероятно, должны быть в отдельных сообщениях. Первый, в частности, касается терминального интерфейса вашей операционной системы и не имеет ничего общего с самим языком программирования C.
@JohnBollinger: это обсуждалось на Stack Overflow много лет назад. В обычных реализациях C EOF нельзя путать с возвратом символа из getchar. Но если char и int имеют одинаковую ширину, например, обе 16 бит, то unsigned char, которое возвращает getchar, автоматически преобразуется в возвращаемый тип int, поэтому 65535 будет преобразовано в −1 (при условии переноса), и будет невозможно отличить символ 65535 от значения EOF исключительно по возвращаемому значению getchar. (Тестирование feof может сделать это.)
@JohnBollinger: см. здесь и здесь.
Принято, @EricPostpischil. Я действительно думаю, что это в значительной степени теоретическая возможность, а не практическая, потому что даже если char имеет тот же размер, что и int в некоторой реализации — скорее всего, под управлением целевой архитектуры — этой реализации не нужно распознавать символы, соответствующие всем значениям в диапазоне типа char. Действительно, эта проблема является веской причиной для того, чтобы такую реализацию не делать. Но вы правы, в принципе такое могло случиться.
double c = getchar(); - что это за безумие?





getchar и putchar работают со значениями unsigned char, а не со значениями char, поэтому объявление c типом char приводит к тому, что допустимый символ 255 путают с EOF.
Чтобы упростить объяснение, этот ответ предполагает обычную реализацию C, за исключением случаев, когда указано: char знаковый и восьмибитный, EOF равен −1 и преобразование в целые типы со знаком по модулю 2w, где w — ширина типа в битах. Стандарт C допускает здесь некоторые вариации, но эти предположения типичны для обычных реализаций C и соответствуют поведению, указанному в вопросе.
Рассмотрим этот код для eof.c из вопроса:
#include <stdio.h>
int main()
{
printf("The part before EOF\n");
putchar(EOF);
printf("The part after EOF\n");
}
Когда эта программа выполняется putchar(EOF), происходит следующее:
putchar преобразует EOF в unsigned char. Это указано в C 2018 7.21.7.3 (через 7.21.7.7 и 7.21.7.8).unsigned char дает 255, потому что преобразование в беззнаковый восьмибитный целочисленный тип переносит по модулю 256, а -1 + 256 = 255.… заменил
int c = getchar();в программе из книги наchar c = getchar();, сохранил, а затем скомпилировал программу как 'copy.out'. Когда я запускаю команду./eof.out | ./copy.outв терминале, я получаю вывод:The part before EOF
Что происходит с c = getchar();, когда считывается байт 255 и оценивается c = getchar():
getchar возвращает 255. Обратите внимание, что это код символа как значение unsigned char согласно C 2018 7.21.7.1 (через 7.21.7.5 и 7.21.7.6).c, 255 преобразуется в тип char. В соответствии с приведенным выше предположением это оборачивает по модулю 256, что дает -1.−1 — это значение EOF, поэтому c != EOF ложно, поэтому цикл завершается, и программа завершается.
Почему не
putchar(EOF); остановить copy.out ? Разве уdoubleне больше байтов, чем уintиchar? что происходит?
С double c значение, присвоенное c, является значением, возвращаемым из getchar; изменений нет из-за того, что тип назначения не может представить все возвращаемые значения getchar. Когда getchar возвращает допустимый код символа 255, c устанавливается на 255, и цикл продолжается. Когда getchar возвращает код -1 для конца файла, c устанавливается в -1, и цикл завершается.
… книга указывает, что должен был быть какой-то сбой, так как я изменил
intнаchar…
Отрывок из книги не говорит, что должен быть какой-то провал. В нем говорится, что EOF — это «значение, которое нельзя спутать ни с одним реальным символом»; это не говорит, что вы не можете преобразовать EOF в char. Если ваша реализация C использует тип unsigned char, преобразование переносит значение по модулю 2w, где w — количество битов в char, обычно восемь, поэтому по модулю 256. Например, -1 отображается в 255. Если ваша реализация C использует знак char, преобразование определяется реализацией. Таким образом, ваша программа eof.c не выводит индикацию конца файла при оценке putchar(EOF). Вместо этого он выводит код символа 255.
Ладно, честно, я пропустил эту часть...
См. это и это относительно Ctrl + 4. Это в основном эквивалентно Ctrl + Break в Windows.