O que é EOF e como ativá-lo? [fechadas]


12

Este é o meu código fonte C.

Quando o construo no Ubuntu, ele começa a obter caracteres, mas não sei como finalizar o programa, pois não termina inserindo ENTERou retornando um carro.

O que significa EOF? Como posso acioná-lo?

Esta fonte também está em um livro 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);
}

4
na linguagem C -1é equivalente a EOF. Ele é definido no /usr/include/stdio.hcomo uma constante macro
Edward Torvalds


@edwardtorvalds entrar -1como entrada não funciona :) #
Sergiy Kolodyazhnyy

Eu acho que o mesmo livro de Dennis Ritchie explica isso.
precisa saber é

Também relevante: unix.stackexchange.com/questions/110240/... (Nenhuma das respostas postadas a esta pergunta é inteiramente correcto.)
fkraiem

Respostas:


22

Tl; dr

Geralmente, você pode "acionar o EOF" em um programa em execução em um terminal com um pressionamento de tecla CTRL+ Dlogo após a última descarga da entrada.


O que significa EOF? Como posso acioná-lo?

EOF significa Fim do arquivo.

"Disparar EOF" nesse caso significa aproximadamente "conscientizar o programa de que nenhuma entrada será enviada".

Nesse caso, como getchar()retornará um número negativo se nenhum caractere for lido, a execução será encerrada.

Mas isso não se aplica apenas ao seu programa específico, mas a muitas ferramentas diferentes.

Em geral, "disparar EOF" pode ser feito com um pressionamento de tecla CTRL+ Dlogo após a última descarga da entrada (ou seja, enviando uma entrada vazia).

Por exemplo, com cat:

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

O que está acontecendo sob o capô ao pressionar CTRL+ Dé que a entrada digitada desde a última liberação de entrada é liberada; quando isso é uma entrada vazia, o read()syscall chamado no STDIN do programa retorna 0, getchar()retorna um número negativo ( -1na biblioteca GNU C) e, por sua vez, é interpretado como EOF 1 .


1 - /programming//a/1516177/4316166


2
A compilação funciona, porque a delimitação por vírgula não é vinculada por estar na mesma linha. Fora isso, grande explicação sobre EOF :)
Paulius Šukys

@ PauliusŠukys Huh, você está certo. Meu C está um pouco enferrujado. :)
kos

1
O iirc EOF não está definido como -1 pelo padrão. É exatamente o que acontece na glibc, por exemplo.
Larkey


1
O EOF 'não consiste em enviar uma "entrada vazia"', e a resposta SO citada não diz o contrário. É um sinal fora da banda. No caso de um terminal, ele é enviado digitando Ctrl / d.
precisa saber é o seguinte

4

TL; DR : EOF não é um caractere, é uma macro usada para avaliar o retorno negativo de uma função de leitura de entrada. Pode-se usar Ctrl+ Dpara enviar EOTcaracteres que forçam o retorno da função-1

Todo programador deve RTFM

Vamos nos referir ao "CA Reference Manual", de Harbison e Steele, 4ª ed. a partir de 1995, página 317:

O número inteiro negativo EOF é um valor que não é uma codificação de um "caractere real". . . Por exemplo, fget (seção 15.6) retorna EOF quando no final do arquivo, porque não há "caractere real" a ser lido.

Essencialmente, EOFnão é um caractere, mas um valor inteiro implementado stdio.hpara representar -1. Portanto, a resposta de kos está correta na medida em que isso é válido, mas não se trata de receber entradas "vazias". Nota importante é que aqui o EOF serve como comparação de valor de retorno (de getchar()), para não significar um caractere real. Os man getcharsuportes que:

VALOR DE RETORNO

fgetc (), getc () e getchar () retornam o caractere lido como uma conversão de caracteres não assinada para um int ou EOF no final do arquivo ou erro.

gets () e fgets () retornam s em caso de sucesso e NULL em erro ou quando o final do arquivo ocorre enquanto nenhum caractere foi lido.

ungetc () retorna c em caso de sucesso ou EOF em caso de erro.

Considere o whileloop - seu objetivo principal é repetir a ação se a condição entre colchetes for verdadeira . Olhe novamente:

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

Basicamente, diz continuar fazendo coisas se c = getchar()retornar um código bem-sucedido ( 0ou acima; é uma coisa comum, tente executar o comando bem-sucedido echo $?e, em seguida, falhe echo $?e veja os números que eles retornam). Portanto, se conseguirmos obter o caractere e atribuir a C, o código de status retornado será 0, a falha será -1. EOFdefine-se como -1. Portanto, quando a condição -1 == -1ocorre, os loops são interrompidos. E quando isso vai acontecer? Quando não há mais caráter para obter, quando c = getchar()falha. Você poderia escrever while ((c = getchar ()) != -1)e ainda funcionaria

Além disso, vamos voltar ao código real, aqui está um trecho de stdio.h

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

Códigos ASCII e EOT

Embora o caractere EOF não seja um caractere real, no entanto, existe um caractere EOT(Fim da transmissão), que possui valor decimal ASCII de 04; está vinculado ao atalho Ctrl+ D(representado também como meta caractere ^D). O caractere de fim da transmissão costumava significar o fechamento de um fluxo de dados quando os computadores eram usados ​​para controlar as conexões telefônicas, daí a denominação "fim da transmissão".

Portanto, é possível enviar esse valor ascii para o programa dessa maneira, observe o $'\04'que é o 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

Assim, podemos dizer que existe, mas não é imprimível

Nota

Muitas vezes esquecemos que no passado os computadores não eram tão versáteis - os designers precisam usar todas as teclas do teclado disponíveis. Portanto, o envio de EOTcaractere com CtrlD ainda está "enviando um caractere", não muito diferente da digitação de letras maiúsculas A, ShiftA, você ainda fornece ao computador uma entrada com as teclas disponíveis. Portanto, a EOT é um personagem real, no sentido de que é proveniente do usuário, é legível por computador (embora não seja imprimível, não é visível por humanos), existe na memória do computador

Comentário do Byte Commander

Se você tentar ler de / dev / null, isso também deve retornar um EOF, certo? Ou o que eu chego lá?

Sim, exatamente certo, porque /dev/nullnão existe um caracter real a ser lido, portanto, ele c = getchar()retornará o -1código e o programa será encerrado imediatamente. Novamente, o comando não retorna EOF. O EOF é apenas uma variável constante igual a -1, que usamos para comparar o código de retorno da função getchar . EOFnão existe como personagem, é apenas um valor estático por dentro 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

Outro prego no caixão

Às vezes, tenta-se provar que EOF é um personagem com um código como este:

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

O problema é que o tipo de dados char pode ser um valor assinado ou não assinado. Além disso, eles são o menor tipo de dados endereçável, o que os torna muito úteis em microcontroladores, onde a memória é limitada. Então, em vez de declarar int foo = 25;, é comum ver em microcontroladores com pouca memória char foo = 25;ou algo semelhante. Além disso, os caracteres podem ser assinados ou não assinados .

Pode-se verificar se o tamanho em bytes com um programa como este:

#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 exatamente é a questão ? O ponto é que o EOF é definido como -1, mas o tipo de dados char pode imprimir valores inteiros .

ESTÁ BEM . . .so e se tentarmos imprimir char como string?

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

Obviamente, um erro, mas mesmo assim, o erro nos dirá algo interessante:

skolodya @ ubuntu: $ gcc EOF.c -o EOF
EOF.c: Na função 'main': EOF.c: 4: 5: aviso: o formato '% s' espera argumento do tipo 'char *', mas o argumento 2 tem tipo 'int' [-Wformat =] printf ("% s", EOF);

Valores hexadecimais

Imprimir EOF como um valor hexadecimal fornece FFFFFFFF, um valor de 16 bits (8 bytes), o complemento de dois de a -1.

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

Resultado:

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

Outra coisa curiosa ocorre com o seguinte código:

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

Se pressionar Shift+ A, obtemos o valor hexadecimal 41, obviamente o mesmo da tabela ASCII. Mas para Ctrl+ D, temos ffffffffnovamente o valor de retorno getchar()armazenado em 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

Consulte outros idiomas

Observe que outro idioma evita essa confusão, porque eles operam na avaliação do status de saída de uma função, não comparando-o com uma macro. Como se lê um arquivo em Java?

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

E o python?

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

Ótimo ponto, de fato, um personagem é enviado de alguma forma em algum momento.
kos

Eu acho que o personagem EOF é algo que foi perdido na tradução, já que não é um personagem real, mas o EOT é um personagem ascii real. Vai saber !
Sergiy Kolodyazhnyy

1
Se você tentar ler /dev/null, isso também deve retornar um EOF, certo? Ou o que eu chego lá?
Byte Commander

O @ByteCommander permite descobrir. Faça cat / dev / null | gato -A.
Sergiy Kolodyazhnyy

@ByteCommander adicionou uma seção que aborda o seu comentário
Sergiy Kolodyazhnyy

2

EOF significa final do arquivo . Embora eu não saiba como acionar o símbolo a seguir, você pode executar o seguinte programa através da canalização de um arquivo, que envia o sinal EOF no final:

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

onde a.outestá sua fonte compilada


1
Promovido isso já, no entanto, em uma nota lateral, o EOF não é um caractere, acho que o equívoco decorre do fato de ser sinalizado através de um pressionamento de tecla CTRL, que geralmente é a maneira de inserir caracteres não imprimíveis. Pelo que entendi, tudo o que realmente acontece é que toda a entrada é liberada e a entrada a ser liberada vazia read()(syscall) retornará 0, que é interpretada como EOF: stackoverflow.com/a/1516177/4316166
kos

@ kos, você está certo, é um sinal afinal.
Paulius Šukys
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.