web-dev-qa-db-fra.com

Qu'est-ce que EOF et comment le déclencher?

Ceci est mon code source C.

Quand je le construis dans Ubuntu, il commence à obtenir des caractères mais je ne sais pas comment terminer le programme, car cela ne se termine pas par la saisie ENTER ou un retour de voiture.

Que signifie EOF? Comment puis-je le déclencher?

Cette source est également sur un livre de 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);
}
10
stackprogramer

Tl; dr

Vous pouvez généralement "déclencher EOF" dans un programme exécuté dans un terminal avec CTRL+D frappe juste après la dernière entrée flush.


Que signifie EOF? Comment puis-je le déclencher?

EOF signifie fin de fichier.

Dans ce cas, "déclencher EOF" signifie en gros "informer le programme que plus aucune entrée ne sera envoyée".

Dans ce cas, puisque getchar() renverra un nombre négatif si aucun caractère n'est lu, l'exécution est terminée.

Mais cela ne s'applique pas seulement à votre programme spécifique, cela s'applique également à de nombreux outils.

En général, "déclencher EOF" peut être fait avec un CTRL+D frappe juste après le dernier flush d’entrée (c’est-à-dire en envoyant une entrée vide).

Par exemple, avec cat:

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

Qu'est-ce qui se passe sous le capot en frappant CTRL+D est-ce que l'entrée saisie depuis le dernier vidage d'entrée est purgée; lorsqu'il s'agit d'une entrée vide, l'appel read() appelé dans le répertoire STDIN du programme renvoie 0, getchar() renvoie un nombre négatif (-1 dans la bibliothèque GNU C) et est à son tour interprété comme EOF1.


1 - https://stackoverflow.com/a/1516177/4316166

20
kos

TL; DR : EOF n'est pas un caractère, c'est une macro utilisée pour évaluer le retour négatif d'une fonction de lecture d'entrée. On peut utiliser Ctrl+D envoyer le caractère EOTqui forcera le retour de la fonction -1

Chaque programmeur doit RTFM

Reportons-nous à "C A Reference Manual", de Harbison et Steele, 4ème éd. à partir de 1995, page 317:

L'entier négatif EOF est une valeur qui n'est pas un codage d'un "caractère réel". . . Par exemple, fget (section 15.6) renvoie EOF à la fin du fichier car il n’ya pas de "caractère réel" à lire.

EOFn'est pas un caractère, mais une valeur entière implémentée dans stdio.h pour représenter -1. Ainsi, la réponse de kos est correcte dans la mesure du possible, mais il ne s'agit pas de recevoir une entrée "vide". Remarque importante: ici EOF sert comme valeur de retour (de getchar()) à titre de comparaison, pour ne pas indiquer un caractère réel. Le man getchar prend en charge cela:

Valeur de retour

fgetc (), getc () et getchar () renvoient le caractère lu sous forme de conversion de caractère non signé en int ou EOF à la fin du fichier ou en cas d'erreur.

gets () et fgets () renvoient s en cas de succès, et NULL en cas d'erreur ou lorsque la fin du fichier survient alors qu'aucun caractère n'a été lu.

ungetc () renvoie c en cas de succès, ou EOF en cas d'erreur.

Considérez la boucle while- son objectif principal est de répéter l'action si la condition entre crochets est vraie. Regarde encore:

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

En gros, continue à faire des choses si c = getchar() renvoie le code qui a réussi (0 ou supérieur; c'est une chose courante en passant, essayez d'exécuter une commande réussie, puis echo $? et ensuite, un échec avec echo $? et de voir les nombres qu'ils renvoient). Donc, si nous obtenons le caractère et l'asservissement avec C, le code d'état renvoyé est 0, échec est -1. EOFest défini comme -1. Par conséquent, lorsque la condition -1 == -1 se produit, les boucles s'arrêtent. Et quand cela va-t-il arriver? Lorsqu'il n'y a plus de caractère à obtenir, lorsque c = getchar() échoue. Vous pourriez écrire while ((c = getchar ()) != -1) et cela fonctionnerait toujours

En outre, revenons au code actuel. Voici un extrait de stdio.h

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

codes ASCII et EOT

Bien que le caractère EOF ne soit pas un caractère réel, il existe cependant un caractère EOT(Fin de la transmission), qui a la valeur ASCII décimale 04; il est lié à Ctrl+D raccourci (également représenté par le méta caractère ^D). L'indicateur de fin de transmission utilisé pour signifier la fermeture d'un flux de données lorsque les ordinateurs étaient utilisés pour contrôler les connexions téléphoniques, d'où le nommage de "fin de transmission".

Il est donc possible d’envoyer cette valeur ascii au programme, notez donc le $'\04' qui correspond à 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

Donc, on peut dire que ça existe, mais ce n’est pas imprimable

Note latérale

Nous oublions souvent que par le passé, les ordinateurs n'étaient pas aussi polyvalents: les concepteurs devaient utiliser toutes les touches du clavier disponibles. Ainsi, l'envoi de EOTcaractère avec CtrlD continue à "envoyer un caractère", ce qui n'est pas si différent de la frappe en majuscule A, ShiftA, vous devez toujours donner à l'ordinateur une entrée avec les clés disponibles. Ainsi, EOT est un personnage réel dans le sens où il provient d'un utilisateur, il est lisible par ordinateur (même s'il n'est pas imprimable, il n'est pas visible par l'homme), il existe dans la mémoire

Commentaire du commandant d'octet

Si vous essayez de lire dans/dev/null, cela devrait également renvoyer un EOF, n'est-ce pas? Ou qu'est-ce que j'y arrive?

Oui, tout à fait à droite, car dans /dev/null il n’ya pas de caractère à lire, donc c = getchar() renverra le code -1 et le programme quittera immédiatement. Encore une fois la commande ne renvoie pas EOF. EOF est simplement une variable constante égale à -1, que nous utilisons pour comparer le code de retour de la fonction getchar . EOFn'existe pas en tant que caractère, c'est juste une valeur statique à l'intérieur de stdio.h.

Démo:

# 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 autre clou dans le cercueil

On essaie parfois de prouver que EOF est un caractère avec un code comme celui-ci:

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

Le problème avec cela est que le type de données char peut être une valeur signée ou non signée. De plus, ils sont le plus petit type de données adressable, ce qui les rend très utiles dans les microcontrôleurs, où la mémoire est limitée. Ainsi, au lieu de déclarer int foo = 25;, il est courant de voir des microcontrôleurs avec une petite mémoire char foo = 25; ou quelque chose de similaire. De plus, les caractères peuvent être signés ou non signés .

On pourrait vérifier que la taille en octets avec un programme comme celui-ci:

#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

Quel est le but ? Le point important est que EOF est défini comme -1, mais le type de données char peut imprimer des valeurs entières.

D'ACCORD . . .so que si nous essayons d'imprimer char en tant que chaîne?

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

Évidemment une erreur, mais néanmoins, l'erreur nous dira quelque chose d'intéressant:

skolodya @ ubuntu: $ gcc EOF.c -o EOF
EOF.c: Dans la fonction 'main': EOF.c: 4: 5: avertissement: le format '% s' attend un argument de type 'char *', mais un argument 2 a le type 'int' [-Wformat =] printf ("% s", EOF);

Valeurs hexadécimales

Imprimer EOF en tant que valeur hexadécimale donne FFFFFFFFname__, une valeur de 16 bits (8 octets), complément de deux d'un -1.

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

Sortie:

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

Une autre chose curieuse se produit avec le code suivant:

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

Si on appuie Shift + A , nous obtenons la valeur hex 41, évidemment identique à celle de la table ASCII. Mais pour Ctrl + D , nous avons ffffffffname__, encore une fois - la valeur de retour de getchar() enregistrée dans cname__.

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

Voir d'autres langues

Notez que les autres langages évitent cette confusion, car ils fonctionnent en évaluant le statut de sortie d'une fonction et non en le comparant à une macro. Comment lire un fichier dans Java?

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

Qu'en est-il du python?

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

EOF signifie fin de fichier . Bien que je ne sache pas comment déclencher le symbole suivant, vous pouvez exécuter le programme suivant en canalisant un fichier, qui envoie le signal EOF à la fin:

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

a.out est votre source compilée

2
Paulius Šukys