клавиш CTRL-D и CTRL-Z «конец файла» показатели служат той же цели на Unix и Windows, систем, но реализованы совершенно по-разному.
В системах Unix (включая клоны Unix, такие как Linux) CTRL-D, официально описанный как символ конца файла, на самом деле является символом-разделителем. Это почти то же самое, что и символ конца строки (обычно возврат каретки или CTRL-M), который используется для разграничения строк. Оба символа сообщают операционной системе, что линия ввода завершена, и чтобы она была доступна программе. Единственное отличие состоит в том, что с символом конца строки символ конца строки (CTRL-J) вставляется в конец входного буфера, чтобы отметить конец строки, в то время как символ конца файла ничего не вставлен ,
Это означает, что при вводе house^D^D
на Unix системный вызов сначала возвращает буфер длиной 5 с 5 символами house
. Когда read
вызывается снова, чтобы получить больше ввода, он затем возвращает буфер длиной 0 без символов в нем. Поскольку нулевая длина, считанная в нормальном файле, указывает, что конец файла был достигнут, библиотечная функция gets
также интерпретирует это как конец файла и прекращает чтение ввода. Однако, поскольку он заполняет буфер 5 символами, он не возвращает NULL, чтобы указать, что он достиг конца файла. И поскольку на самом деле он фактически не дошел до конца файла, поскольку терминальные устройства не являются фактически файлами, дальнейшие вызовы gets
после этого будут делать дальнейшие звонки read
, которые возвратят любые последующие символы, которые пользователь набирает.
В Windows CTRL-Z обрабатывается по-разному. Самое большое различие заключается в том, что он не обрабатывается специально операционной системой вообще. Когда вы вводите house^Z^Z^M
на Windows, только символ возврата каретки получает специальную обработку. Как и в Unix, возврат каретки делает типизированную линию доступной для программы, хотя в этом случае возврат каретки и подача строки добавляются в буфер для маркировки конца строки. Поэтому результатом является то, что функция ReadFile
возвращает 9-байтовый буфер с 9 символами house^Z^Z^M^J
.
Это на самом деле сама программа, в частности библиотека времени выполнения C, которая специально относится к CTRL-Z. В случае библиотеки времени выполнения Microsoft C, когда он видит символ CTRL-Z в буфере, возвращаемом ReadFile
, он рассматривает его как маркер конца файла и игнорирует все остальное после него. Используя пример в предыдущем абзаце, gets
заканчивает вызов ReadFile
, чтобы получить больше ввода, потому что тот факт, что его видел символ CTRL-Z, не запоминается при чтении с консоли (или на другом устройстве), и он еще не видел конца -of-line (который был проигнорирован). Если вы снова нажмете клавишу Enter, gets
вернется с буфером, заполненным 7 байтами house^Z\0
(добавив 0 байт, чтобы указать конец строки). По умолчанию он делает то же самое при чтении из обычных файлов, если в файле появляется символ CTRL-Z, он и все после его игнорирования. Это для обратной совместимости с CP/M, которая поддерживает только файлы длиной, которые были кратными 128, и использовала CTRL-Z, чтобы отметить, где должны были закончить текстовые файлы.
Обратите внимание, что описанное выше поведение Unix и Windows - это обычная обработка по умолчанию для ввода пользователем. Обработка Unix для CTRL-D происходит только при чтении с терминала в каноническом режиме, и можно изменить символ «конец файла» на что-то другое. В Windows операционная система никогда не обрабатывает CTRL-Z специально, но независимо от того, выполняется ли библиотека выполнения C или нет, зависит от того, читается ли поток FILE в текстовом или двоичном режиме. Вот почему в переносных программах вы должны всегда включать символ b
в строку режима при открытии двоичных файлов (например, fopen("foo.gif", "rb")
).
это выражение: '|| ! feof (stdin)) 'не имеет никакого полезного эффекта. Главным образом потому, что функция: 'feof()' проверяет, пытался ли код прочесть предыдущий EOF, и это выражение проверяется только при обнаружении EOF, поэтому всегда будет false. Поскольку эта функция НЕ делает то, что ожидается (обычно), настоятельно рекомендуем никогда не использовать ее. – user3629249
это выражение: '* curr ++' может/будет проблемой. Проблема связана с приоритетом операторов в C. Предложите: '* curr = (char) c; curr ++; ' – user3629249
Я использовал! feof (stdin), чтобы проверить, не возникла ли ошибка чтения вместо eof. Я просто попытался подражать функции gets (...), чтобы лучше изолировать источник моего сомнения (то есть getchar()) –