Cos'è l'EOF e come attivarlo? [chiuso]


12

Questo è il mio codice sorgente C.

Quando lo costruisco in Ubuntu, inizia a ottenere caratteri ma non so come terminare il programma, poiché non termina con l'inserimento ENTERo con un ritorno a capo .

Cosa significa EOF? Come posso attivarlo?

Questa fonte è anche su un libro di Dennis Ritchie:

#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
in linguaggio C -1equivale a EOF. È definito /usr/include/stdio.hcome una costante macro
Edward Torvalds,


@edwardtorvalds che entra -1come input non funziona :)
Sergiy Kolodyazhnyy

Penso che lo stesso libro di Dennis Ritchie lo spieghi.
Andy256,

Rilevante anche: unix.stackexchange.com/questions/110240/… (Nessuna delle risposte inviate a questa domanda è del tutto corretta.)
fkraiem

Risposte:


22

Tl; dr

In genere è possibile "attivare EOF" in un programma in esecuzione in un terminale con una CTRLsequenza di Dtasti + subito dopo l'ultimo flush di input.


Cosa significa EOF? Come posso attivarlo?

EOF significa End-Of-File.

"Attivare EOF" in questo caso significa approssimativamente "rendere il programma consapevole che non verrà inviato più input".

In questo caso, poiché getchar()restituirà un numero negativo se non viene letto alcun carattere, l'esecuzione verrà terminata.

Ma questo non si applica solo al tuo programma specifico, si applica a molti strumenti diversi.

In generale, "l'attivazione di EOF" può essere eseguita con la pressione di un tasto CTRL+ Dsubito dopo l'ultimo flush dell'input (ovvero inviando un input vuoto).

Ad esempio con cat:

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

Quello che sta succedendo sotto il cofano quando si preme CTRL+ Dè che l'input digitato dall'ultimo flush dell'input è flush; quando si tratta di un input vuoto, la read()syscall richiamata sul programma STDIN ritorna 0, getchar()restituisce un numero negativo ( -1nella libreria GNU C) e questo viene a sua volta interpretato come EOF 1 .


1 - /programming//a/1516177/4316166


2
La compilazione funziona, poiché la delimitazione delle virgole non è vincolata dall'essere nella stessa riga. A parte questo, un'ottima spiegazione su EOF :)
Paulius Šukys,

@ PauliusŠukys Huh, hai ragione. La mia C è un po 'arrugginita. :)
kos

1
iirc EOF non è definito come -1 per lo standard. Ad esempio, è proprio quello che succede in glibc.
larkey,


1
EOF non consiste nell'invio di un "input vuoto" 'e la risposta SO citata non dice diversamente. È un segnale fuori banda. Nel caso di un terminale, viene inviato digitando Ctrl / d.
user207421

4

TL; DR : EOF non è un carattere, è una macro utilizzata per valutare il ritorno negativo di una funzione di input-reading. Si può usare Ctrl+ Dper inviare un EOTcarattere che forzerà il ritorno della funzione-1

Ogni programmatore deve RTFM

Facciamo riferimento al "Manuale di riferimento CA", di Harbison e Steele, 4a ed. dal 1995, pagina 317:

L'intero negativo EOF è un valore che non è una codifica di un "carattere reale". . . Ad esempio fget (sezione 15.6) restituisce EOF alla fine del file, perché non esiste un "carattere reale" da leggere.

Essenzialmente EOFnon è un carattere, ma piuttosto un valore intero implementato stdio.hper rappresentare -1. Pertanto, la risposta di kos è corretta, ma non si tratta di ricevere input "vuoti". Nota importante è che qui EOF funge da confronto del valore di ritorno (di getchar()), non per indicare un carattere reale. I man getcharsupporti che:

VALORE DI RITORNO

fgetc (), getc () e getchar () restituiscono il carattere letto come cast di caratteri non firmato a un int o EOF alla fine del file o dell'errore.

gets () e fgets () restituiscono s in caso di successo e NULL in caso di errore o quando si verifica la fine del file mentre non sono stati letti caratteri.

ungetc () restituisce c in caso di successo o EOF in caso di errore.

Considera il whileciclo: il suo scopo principale è ripetere l'azione se la condizione tra parentesi è vera . Guarda di nuovo:

while ((c = getchar ()) != EOF)

Fondamentalmente dice che continua a fare cose se c = getchar()restituisce codice di successo ( 0o superiore; è una cosa comune tra l'altro, prova a eseguire il comando di successo, quindi echo $?e poi fallisce echo $?e vedi i numeri che restituiscono). Quindi, se otteniamo correttamente il carattere e valutiamo C, il codice di stato restituito è 0, l'errore è -1. EOFè definito come -1. Pertanto, quando si -1 == -1verifica la condizione , i loop si arrestano. E quando succederà? Quando non c'è più personaggio da ottenere, quando c = getchar()fallisce. Potresti scrivere while ((c = getchar ()) != -1)e funzionerebbe ancora

Inoltre, torniamo al codice attuale, ecco un estratto da stdio.h

/* End of file character.
   Some things throughout the library rely on this being -1.  */
#ifndef EOF
# define EOF (-1)
#endif

Codici ASCII ed EOT

Sebbene il carattere EOF non sia un carattere reale, tuttavia, esiste un carattere EOT(End of Transmission), che ha un valore decimale ASCII di 04; è collegato a Ctrl+ Dscorciatoia (rappresentato anche come meta personaggio ^D). Il carattere di fine trasmissione utilizzato per indicare la chiusura di un flusso di dati nel passato quando i computer venivano utilizzati per controllare le connessioni telefoniche, da cui la denominazione di "fine della trasmissione".

Quindi è possibile inviare quel valore ASCII al programma in questo modo, notare $'\04'quale è l'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

Quindi, possiamo dire che esiste, ma non è stampabile

Nota a margine

Spesso dimentichiamo che in passato i computer non erano così versatili: i progettisti devono utilizzare tutti i tasti disponibili. Pertanto, l'invio di EOTcaratteri con CtrlD è ancora "invio di un carattere", non diversamente dalla digitazione della maiuscola A, ShiftA, si fa comunque dare al computer un input con i tasti disponibili. Quindi EOT è un vero personaggio nel senso che proviene da un utente, è leggibile dal computer (anche se non stampabile, non visibile dall'uomo), esiste nella memoria del computer

Commento di Byte Commander

Se provi a leggere da / dev / null, anche questo dovrebbe restituire un EOF, giusto? O cosa ci arrivo?

Sì, esattamente, perché in /dev/nullnon c'è un carattere reale da leggere, quindi c = getchar()restituirà il -1codice e il programma verrà chiuso immediatamente. Ancora una volta il comando non restituisce EOF. EOF è solo una variabile costante uguale a -1, che usiamo per confrontare il codice di ritorno della funzione getchar . EOFnon esiste come personaggio, è solo un valore statico all'interno stdio.h.

demo:

# 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

Un altro chiodo nella bara

A volte si tenta di provare che EOF è un personaggio con un codice come questo:

#include <stdio.h>
int main(void)
{
    printf("%c", EOF);
    return 0;
}

Il problema è che il tipo di dati char può essere un valore con o senza segno. Inoltre, sono i tipi di dati indirizzabili più piccoli che li rendono molto utili nei microcontrollori, dove la memoria è limitata. Quindi invece di dichiarare int foo = 25;è comune vedere nei microcontrollori con poca memoria char foo = 25;o qualcosa di simile. Inoltre, i caratteri possono essere firmati o non firmati .

Si potrebbe verificare che la dimensione in byte con un programma come questo:

#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

Qual è esattamente il punto? Il punto è che EOF è definito come -1, ma il tipo di dati char può stampare valori interi .

OK . . .e cosa succede se proviamo a stampare char come stringa?

#include <stdio.h>
int main(void)
{
    printf("%s", EOF);
    return 0;
}

Ovviamente un errore, ma comunque, ci dirà qualcosa di interessante:

skolodya @ ubuntu: $ gcc EOF.c -o EOF
EOF.c: nella funzione 'principale': EOF.c: 4: 5: avviso: il formato '% s' prevede l'argomento di tipo 'char *', ma l'argomento 2 ha digitare 'int' [-Wformat =] printf ("% s", EOF);

Valori esadecimali

La stampa di EOF come valore esadecimale dà FFFFFFFF, un valore di 16 bit (8 byte), due complimenti di a -1.

#include <stdio.h>
int main(void)
{
    printf("This is EOF: %X\n", EOF);
    printf("This is Z: %X\n",'Z');
    return 0;
}

Produzione:

DIR:/xieerqi
skolodya@ubuntu:$ ./EOF                                                        
This is EOF: FFFFFFFF
This is Z: 5A

Un'altra cosa curiosa si verifica con il seguente codice:

#include <stdio.h>
int main(void)
{
   char c;
   if (c = getchar())
    printf ("%x",c);
    return 0;
}

Se si preme Shift+ A, si ottiene il valore esadecimale 41, ovviamente uguale alla tabella ASCII. Ma per Ctrl+ D, abbiamo ffffffff, ancora una volta - il valore restituito di getchar()stored in 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

Fare riferimento ad altre lingue

Si noti che altre lingue evitano questa confusione, poiché operano sulla valutazione di uno stato di uscita della funzione, non sul confronto con una macro. Come si legge un file in Java?

    File inputFile  = new File (filename);
    Scanner readFile = new Scanner(inputFile);
    while (readFile.hasNext())
        { //more code bellow  }

Che ne dici di Python?

with open("/etc/passwd") as file:
     for line in file:
          print line

Ottimo punto, in effetti un personaggio viene inviato in qualche modo ad un certo punto.
kos

Penso che il personaggio EOF sia qualcosa che è stato perso nella traduzione, dal momento che non è un personaggio reale, ma EOT è un personaggio reale, ascii. Vai a capire !
Sergiy Kolodyazhnyy,

1
Se provi a leggere /dev/null, dovrebbe restituire anche un EOF, giusto? O cosa ci arrivo?
Byte comandante

@ByteCommander lo fa scoprire. Fai cat / dev / null | gatto -A.
Sergiy Kolodyazhnyy,

@ByteCommander ha aggiunto la sezione relativa al tuo commento
Sergiy Kolodyazhnyy

2

EOF sta per fine del file . Mentre non so come attivare il seguente simbolo, è possibile eseguire il seguente programma tramite il piping di un file, che invia il segnale EOF alla fine:

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

dov'è la a.outtua fonte compilata


1
Ho già votato a fondo, tuttavia su una nota a margine EOF non è un personaggio, penso che l'idea sbagliata derivi dal fatto che viene segnalato tramite una sequenza di tasti CTRL, che di solito è il modo di inserire caratteri non stampabili. A quanto ho capito, tutto ciò che accade realmente è che tutto l'input è svuotato ed essendo l'input da svuotare vuoto read()(syscall) tornerà 0, che viene interpretato come EOF: stackoverflow.com/a/1516177/4316166
kos

@kos, hai ragione, dopo tutto è un segnale.
Paulius Šukys,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.