TL; DR : EOF не є символом, це макрос, який використовується для оцінки негативного повернення функції введення-читання. Можна використовувати Ctrl+ Dдля надсилання EOT
символу, який змусить повернути функцію-1
Кожен програміст повинен RTFM
Звернімось до "Довідкового посібника CA", від Harbison and Steele, 4-е видання. від 1995 р., сторінка 317:
Негативне ціле число EOF - це значення, яке не є кодуванням "реального символу". . . Наприклад, fget (розділ 15.6) повертає EOF у кінці файлу, оскільки немає "реального символу" для читання.
По суті EOF
це не символ, а ціле значення, реалізоване в stdio.h
зображенні -1
. Таким чином, відповідь kos є правильною, наскільки це стосується, але справа не в отриманні "порожнього" введення. Важливе зауваження, що тут EOF служить повертається значенням (в getchar()
) порівняннях, не означає фактичний характер. В man getchar
опорах , що:
ПОВЕРНЕННЯ ЦІННОСТІ
fgetc (), getc () та getchar () повертають символ, прочитаний у вигляді безпідписаного символу, до кінця файлу чи помилки.
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
символ (End of Transmission), який має десятичне значення 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 є реальним персонажем у тому сенсі, який він походить від користувача, він читається комп'ютером (хоча не для друку, не видно людині), він існує в пам'яті комп'ютера
Коментар командира байт
Якщо ви спробуєте прочитати з / 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 може друкувати цілі значення .
В ПОРЯДКУ . . .так що робити, якщо ми спробуємо надрукувати 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
як макроконстанта