Що таке EOF і як його запустити? [зачинено]


12

Це мій вихідний код C.

Коли я будую його в Ubuntu, він починає отримувати символи, але я не знаю, як закінчити програму, оскільки вона не закінчується введенням ENTERабо поверненням каретки.

Що означає EOF? Як я можу його запустити?

Це джерело також у книзі Денніса Річі:

#include <stdio.h>
    /* count digits, white space, others */
main ()
{
  int c, i, nwhite, nother;
  int ndigit[10];
  nwhite = nother = 0;
  for (i = 0; i < 10; ++i)
    ndigit[i] = 0;
  while ((c = getchar ()) != EOF)
    if (c >= '0' && c <= '9')
      ++ndigit[c - '0'];
    else if (c == ' ' || c == '\n' || c == '\t')
      ++nwhite;
    else
      ++nother;
  printf ("digits =");
  for (i = 0; i < 10; ++i)
    printf (" %d", ndigit[i]);
  printf (", white space = %d, other = %d\n", nwhite, nother);
}

4
мовою С -1еквівалентно EOF. Визначається /usr/include/stdio.hяк макроконстанта
Едвард Торвальдс


@edwardtorvalds введення -1як вхід не працює :)
Сергій Колодяжний

Я думаю, що та сама книга Денніса Річі пояснює це.
andy256

Також актуально: unix.stackexchange.com/questions/110240/… (жодна з відповідей, розміщених на це запитання, не є абсолютно правильною.)
fkraiem

Відповіді:


23

Тл; д-р

Як правило, ви можете "запустити EOF" в програмі, що працює в терміналі з натисканням клавіші CTRL+ Dвідразу після останнього потоку входу.


Що означає EOF? Як я можу його запустити?

EOF означає "End-Of-File".

"Запуск EOF" в цьому випадку приблизно означає "давати програмі усвідомлювати, що більше вхідних даних не надсилатиметься".

У цьому випадку з getchar() поверне від'ємне число, якщо жоден символ не буде прочитаний, виконання припиняється.

Але це не стосується лише вашої конкретної програми, вона стосується багатьох різних інструментів.

Взагалі "запуск EOF" може бути зроблено натисканням клавіші CTRL+ Dвідразу після останнього введення (тобто шляхом надсилання порожнього вводу).

Наприклад з cat:

% cat >file # Hit ENTER
foo # Hit ENTER and CTRL+D
% 

Що відбувається під кришкою при натисканні CTRL+, Dце те, що вхід, що вводиться з моменту останнього потоку входу, змивається; коли це буває порожнім входом , повертається read()системний виклик, викликаний STDIN програми 0, getchar()повертає негативне число ( -1у бібліотеці GNU C), і це, в свою чергу, інтерпретується як EOF 1 .


1 - /programming//a/1516177/4316166


2
Компіляція працює, оскільки розмежування комами не пов'язане знаходженням в одному рядку. Окрім цього, велике пояснення на EOF :)
Пауліус Шукіс

@ PauliusŠukys Гм, ти маєш рацію. Мій C трохи іржавий. :)
kos

1
iirc EOF не визначено як -1 на стандарт. Це просто те, що відбувається, наприклад, у glibc.
larkey


1
EOF не полягає у надсиланні "порожнього вводу" ", і відповідь, яку ви цитуєте, не говорить про інше. Це сигнал поза діапазону. У випадку терміналу він надсилається, ввівши Ctrl / d.
користувач207421

4

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 у вигляді шістнадцяткового значення дає FFFFFFFF16-бітове (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

Чудова точка, справді персонаж якось надсилається в якийсь момент.
kos

Я думаю, що символ EOF - це те, що було втрачено в перекладі, оскільки це не фактичний персонаж, але EOT - це фактичний, ascii персонаж. Піди розберися !
Сергій Колодяжний

1
Якщо ви спробуєте прочитати з /dev/null, це також має повернути EOF, правда? Або що я туди дістаю?
Байт-командир

@ByteCommander дозволяє дізнатися це. Чи котик / dev / null | кішка -А.
Сергій Колодяжний

@ByteCommander додав розділ, який стосується вашого коментаря
Сергій Колодяжний,

2

EOF означає кінець файлу . Хоча я не знаю, як запустити наступний символ, ви можете запустити наступну програму через конфігурацію файлу, який в кінці посилає сигнал EOF :

echo "Some sample text" | ./a.out

де a.outваше зібране джерело


1
Це вже було схвалено, однак на сторонній ноті EOF не є символом, я думаю, що помилкове уявлення виникає з того, що повідомляється натисканням клавіші CTRL, що, як правило, є способом введення символів, що не друкуються. Як я розумію, все, що насправді трапляється, це те, що весь вхід read()проміщено, і повернення входу порожнім (syscall) повернеться 0, що інтерпретується як EOF: stackoverflow.com/a/1516177/4316166
kos

@kos, ти маєш рацію, це сигнал після закінчення.
Паулій Шукіс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.