TL; DR : EOF - это не символ, это макрос, используемый для оценки отрицательного возврата функции чтения ввода. Можно использовать Ctrl+, Dчтобы отправить EOT
символ, который заставит функцию вернуть-1
Каждый программист должен RTFM
Давайте обратимся к «Справочному руководству CA» Harbison and Steele, 4-е изд. с 1995 г., стр. 317:
Отрицательное целое число EOF - это значение, которое не является кодировкой «реального символа». , , Например, fget (раздел 15.6) возвращает EOF в конце файла, потому что нет «реального символа» для чтения.
По сути EOF
это не символ, а скорее целое значение реализуется в stdio.h
представлять -1
. Таким образом, ответ Коса является правильным, но речь идет не о получении «пустого» ввода. Важно отметить, что здесь EOF служит для сравнения возвращаемого значения (of getchar()
), а не для обозначения фактического символа. Поддержки, man getchar
которые:
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
fgetc (), getc () и getchar () возвращают символ, прочитанный как символ без знака, приведенный к int или EOF в конце файла или ошибки.
get () и fgets () возвращают s в случае успеха и NULL в случае ошибки или когда происходит конец файла, когда символы не были прочитаны.
ungetc () возвращает c в случае успеха или EOF в случае ошибки.
Рассмотрим while
цикл - его основная цель - повторить действие, если условие в скобках выполнено . Посмотри снова:
while ((c = getchar ()) != EOF)
По сути, он говорит, что продолжайте делать что-то, если c = getchar()
возвращает успешный код ( 0
или выше; кстати, это обычное дело, попробуйте echo $?
выполнить успешную команду, затем не удалось echo $?
и посмотрите числа, которые они возвращают). Поэтому, если мы успешно получим символ и добавим C, возвращенный код состояния будет равен 0, а ошибка - -1. EOF
определяется как -1
. Поэтому, когда -1 == -1
возникает условие , цикл останавливается. И когда это произойдет? Когда нет больше персонажа, чтобы получить, когда c = getchar()
не удается. Вы могли бы написать, while ((c = getchar ()) != -1)
и это все еще будет работать
Кроме того, давайте вернемся к фактическому коду, вот выдержка из stdio.h
/* End of file character.
Some things throughout the library rely on this being -1. */
#ifndef EOF
# define EOF (-1)
#endif
Коды ASCII и EOT
Хотя символ EOF не является действительным символом, тем не менее, существует символ EOT
(Конец передачи), который имеет десятичное значение ASCII 04; он связан с ярлыком Ctrl+ D(представлен также как метасимвол ^D
). Характер окончания передачи использовался для обозначения закрытия потока данных в обратном направлении, когда компьютеры использовались для контроля телефонных соединений, отсюда и название «конец передачи».
Таким образом, можно отправить это значение ascii в программу следующим образом, обратите внимание на то, $'\04'
что является EOT:
skolodya@ubuntu:$ ./a.out <<< "a,b,c $'\04'"
digits = 1 0 0 0 1 0 0 0 0 0, white space = 2, other = 9
Таким образом, мы можем сказать, что он существует, но это не для печати
Примечание
Мы часто забываем, что в прошлом компьютеры не были такими универсальными - дизайнеры должны использовать каждую доступную клавиатуру. Таким образом, отправка EOT
символа с помощью CtrlD по-прежнему является «отправкой символа», в отличие от ввода прописной буквы A, ShiftA, вы все равно заставляете компьютер вводить данные с помощью доступных клавиш. Таким образом, EOT - это реальный символ в том смысле, что он исходит от пользователя, он читается компьютером (хотя не для печати, не виден людьми), он существует в компьютерной памяти
Комментарий Byte Commander
Если вы попытаетесь прочитать из / dev / null, это также должно вернуть EOF, верно? Или что я получу там?
Да, совершенно верно, потому /dev/null
что нет никакого действительного символа, который нужно прочитать, следовательно, он c = getchar()
вернет -1
код, и программа сразу же закроется. Снова команда не возвращает EOF. EOF - это просто постоянная переменная, равная -1, которую мы используем для сравнения кода возврата функции getchar . EOF
не существует как символ, это просто статическое значение внутри stdio.h
.
Демо-версия:
# cat /dev/null shows there's no readable chars
DIR:/xieerqi
skolodya@ubuntu:$ cat /dev/null | cat -A
# Bellow is simple program that will open /dev/null for reading. Note the use of literal -1
DIR:/xieerqi
skolodya@ubuntu:$ cat readNull.c
#include<stdio.h>
void main()
{
char c;
FILE *file;
file = fopen("/dev/null", "r");
if (file)
{
printf ("Before while loop\n");
while ((c = getc(file)) != -1)
putchar(c);
printf("After while loop\n");
fclose(file);
}
}
DIR:/xieerqi
skolodya@ubuntu:$ gcc readNull.c -o readNull
DIR:/xieerqi
skolodya@ubuntu:$ ./readNull
Before while loop
After while loop
Еще один гвоздь в гробу
Иногда пытаются доказать, что EOF - это символ с кодом, подобным этому:
#include <stdio.h>
int main(void)
{
printf("%c", EOF);
return 0;
}
Проблема в том, что тип данных char может иметь значение со знаком или без знака. Кроме того, они являются наименьшим адресуемым типом данных, что делает их очень полезными в микроконтроллерах, где память ограничена. Таким образом, вместо декларации int foo = 25;
обычно можно увидеть в микроконтроллерах с небольшим объемом памяти char foo = 25;
или что-то подобное. Кроме того, символы могут быть подписаны или не подписаны .
Можно проверить, что размер в байтах с программой, как это:
#include <stdio.h>
int main(void)
{
printf("Size of int: %lu\n",sizeof(int));
printf("Sieze of char: %lu\n",sizeof(char));
//printf("%s", EOF);
return 0;
}
skolodya@ubuntu:$ ./EOF
Size of int: 4
Sieze of char: 1
Какой именно смысл? Дело в том, что EOF определяется как -1, но тип данных char может печатать целочисленные значения .
OK . , .то, что если мы попытаемся напечатать char как строку?
#include <stdio.h>
int main(void)
{
printf("%s", EOF);
return 0;
}
Очевидно, это ошибка, но, тем не менее, ошибка скажет нам кое-что интересное:
skolodya @ ubuntu: $ gcc EOF.c -o EOF
EOF.c: в функции 'main': EOF.c: 4: 5: предупреждение: формат '% s' ожидает аргумент типа 'char *', но аргумент 2 имеет тип 'int'
[-Wformat =] printf ("% s", EOF);
Шестнадцатеричные значения
Печать EOF в виде шестнадцатеричного значения дает FFFFFFFF
16-битное (8-байтовое) значение, два комплимента a -1
.
#include <stdio.h>
int main(void)
{
printf("This is EOF: %X\n", EOF);
printf("This is Z: %X\n",'Z');
return 0;
}
Выход:
DIR:/xieerqi
skolodya@ubuntu:$ ./EOF
This is EOF: FFFFFFFF
This is Z: 5A
Еще одна любопытная вещь происходит со следующим кодом:
#include <stdio.h>
int main(void)
{
char c;
if (c = getchar())
printf ("%x",c);
return 0;
}
Если нажать Shift+ A, мы получим шестнадцатеричное значение 41, очевидно, такое же, как в таблице ASCII. Но для Ctrl+ Dмы ffffffff
снова получаем возвращаемое значение, getchar()
хранящееся в c
.
DIR:/xieerqi
skolodya@ubuntu:$ gcc EOF.c -o ASDF.asdf
DIR:/xieerqi
skolodya@ubuntu:$ ./ASDF.asdf
A
41
DIR:/xieerqi
skolodya@ubuntu:$ ./ASDF.asdf
ffffffff
Обратитесь к другим языкам
Обратите внимание, что другие языки избегают этой путаницы, потому что они работают с оценкой состояния завершения функции, а не сравнивают ее с макросом. Как читать файл в Java?
File inputFile = new File (filename);
Scanner readFile = new Scanner(inputFile);
while (readFile.hasNext())
{ //more code bellow }
Как насчет питона?
with open("/etc/passwd") as file:
for line in file:
print line
-1
является эквивалентом EOF. Он определен/usr/include/stdio.h
как макроконстанция