Apa itu EOF dan bagaimana memicunya? [Tutup]


12

Ini adalah kode sumber C saya.

Ketika saya membangunnya di Ubuntu, ia mulai mendapatkan karakter tetapi saya tidak tahu bagaimana mengakhiri program, karena tidak berakhir dengan memasukkan ENTERatau carriage return.

Apa artinya EOF? Bagaimana saya bisa memicunya?

Sumber ini juga ada di buku karya 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
dalam bahasa C -1setara dengan EOF. Ini didefinisikan /usr/include/stdio.hsebagai konstanta makro
Edward Torvalds


@edwardtorvalds masuk -1sebagai input tidak berfungsi :)
Sergiy Kolodyazhnyy

Saya pikir buku Dennis Ritchie yang sama menjelaskan hal ini.
andy256

Juga relevan: unix.stackexchange.com/questions/110240/… (Tidak ada jawaban yang diposting untuk pertanyaan ini sepenuhnya benar.)
fkraiem

Jawaban:


22

Tl; dr

Anda biasanya dapat "memicu EOF" dalam program yang berjalan di terminal dengan CTRL+ Dkeystroke tepat setelah input flush terakhir.


Apa artinya EOF? Bagaimana saya bisa memicunya?

EOF berarti End-Of-File.

"Triggering EOF" dalam hal ini kira-kira berarti "membuat program sadar bahwa tidak ada lagi input yang akan dikirim".

Dalam hal ini, karena getchar()akan mengembalikan angka negatif jika tidak ada karakter yang dibaca, eksekusi dihentikan.

Tetapi ini tidak hanya berlaku untuk program spesifik Anda, tetapi juga berlaku untuk berbagai alat.

Secara umum "memicu EOF" dapat dilakukan dengan CTRL+ Dkeystroke tepat setelah input flush terakhir (yaitu dengan mengirim input kosong).

Misalnya dengan cat:

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

Apa yang terjadi di bawah kap ketika menekan CTRL+ Dadalah bahwa input yang diketik sejak flush input terakhir memerah; ketika ini merupakan input kosong yang read()dipanggil syscall pada pengembalian program STDIN 0, getchar()mengembalikan angka negatif ( -1dalam pustaka GNU C) dan ini pada gilirannya ditafsirkan sebagai EOF 1 .


1 - /programming//a/1516177/4316166


2
Kompilasi bekerja, karena pembatasan koma tidak terikat dengan berada di baris yang sama. Selain itu, penjelasan hebat tentang EOF :)
Paulius Šukys

@ PauliusŠukys Huh, kau benar. C saya agak berkarat. :)
kos

1
iirc EOF tidak didefinisikan -1 per standar. Itu hanya apa yang terjadi di glibc misalnya.
Larkey


1
EOF tidak 'terdiri dalam mengirim "input kosong"', dan jawaban SO yang Anda kutip tidak mengatakan sebaliknya. Ini adalah sinyal band keluar. Dalam kasus terminal dikirim dengan mengetikkan Ctrl / d.
user207421

4

TL; DR : EOF bukan karakter, ini adalah makro yang digunakan untuk mengevaluasi pengembalian negatif dari fungsi membaca-input. Orang dapat menggunakan Ctrl+ Duntuk mengirim EOTkarakter yang akan memaksa fungsi kembali-1

Setiap programmer harus RTFM

Mari kita merujuk ke "Manual Referensi CA", oleh Harbison dan Steele, edisi ke-4. dari 1995, halaman 317:

EOF bilangan bulat negatif adalah nilai yang bukan merupakan pengkodean "karakter nyata". . . Misalnya fget (bagian 15.6) mengembalikan EOF ketika pada akhir file, karena tidak ada "karakter nyata" untuk dibaca.

Pada dasarnya EOFbukan karakter, melainkan nilai integer yang diterapkan stdio.huntuk mewakili -1. Jadi, jawaban kos itu benar sejauh yang dikatakan, tetapi ini bukan tentang menerima input "kosong". Catatan penting adalah bahwa di sini EOF berfungsi sebagai nilai pengembalian (dari getchar()) perbandingan, bukan untuk menandakan karakter yang sebenarnya. The man getcharmendukung bahwa:

NILAI KEMBALI

fgetc (), getc () dan getchar () mengembalikan karakter yang dibaca sebagai karakter yang tidak ditandatangani ke int atau EOF di akhir file atau kesalahan.

mendapat () dan fgets () mengembalikan s pada keberhasilan, dan NULL pada kesalahan atau ketika akhir file terjadi saat tidak ada karakter yang telah dibaca.

ungetc () mengembalikan c saat berhasil, atau EOF jika salah.

Pertimbangkan whileloop - tujuan utamanya adalah mengulangi tindakan jika kondisi dalam tanda kurung benar . Lihat lagi:

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

Itu pada dasarnya mengatakan tetap melakukan hal-hal jika c = getchar()mengembalikan kode yang berhasil ( 0atau di atas; itu adalah hal yang umum, coba jalankan perintah yang berhasil, echo $?kemudian gagal echo $?dan lihat angka mereka kembali). Jadi jika kita berhasil mendapatkan karakter dan assing ke C, kode status yang dikembalikan adalah 0, gagal adalah -1. EOFdidefinisikan sebagai -1. Karena itu ketika kondisi -1 == -1terjadi, loop berhenti. Dan kapan itu akan terjadi? Ketika tidak ada lagi karakter yang didapat, saat c = getchar()gagal. Anda bisa menulis while ((c = getchar ()) != -1)dan itu masih akan berhasil

Juga, mari kita kembali ke kode aktual, ini kutipan dari stdio.h

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

Kode dan EOT ASCII

Meskipun karakter EOF bukan karakter aktual, namun, ada karakter EOT(End of Transmission), yang memiliki nilai desimal ASCII dari 04; itu ditautkan ke Ctrl+ Dpintasan (diwakili juga sebagai karakter meta ^D). Akhir dari karakter transmisi digunakan untuk menandakan penutupan aliran data kembali ketika komputer digunakan untuk mengontrol koneksi telepon, karenanya penamaan "end of transmission".

Jadi dimungkinkan untuk mengirim nilai ascii ke program seperti itu, perhatikan $'\04'EOT yang mana:

skolodya@ubuntu:$ ./a.out  <<< "a,b,c $'\04'"                                  
digits = 1 0 0 0 1 0 0 0 0 0, white space = 2, other = 9

Dengan demikian, kita dapat mengatakan bahwa itu memang ada, tetapi tidak dapat dicetak

Catatan Samping

Kita sering lupa bahwa di masa lalu komputer tidak serba guna - desainer harus menggunakan setiap tombol keyboard yang tersedia. Dengan demikian, mengirim EOTkarakter dengan CtrlD masih "mengirim karakter", tidak seperti mengetik huruf A, ShiftA, Anda masih membuat memberi komputer input dengan kunci yang tersedia. Jadi EOT adalah karakter nyata dalam arti bahwa itu memang berasal dari pengguna, dapat dibaca oleh komputer (meskipun tidak dapat dicetak, tidak terlihat oleh manusia), itu ada dalam memori komputer

Komentar Byte Commander

Jika Anda mencoba membaca dari / dev / null, itu seharusnya mengembalikan EOF juga, kan? Atau apa yang saya dapatkan di sana?

Ya, tepat sekali, karena di /dev/nullsana tidak ada karakter aktual untuk dibaca, maka itu c = getchar()akan mengembalikan -1kode, dan program akan segera berhenti. Sekali lagi perintah tidak mengembalikan EOF. EOF hanyalah variabel konstan sama dengan -1, yang kami gunakan untuk membandingkan kode pengembalian fungsi getchar . EOFtidak ada sebagai karakter, itu hanya nilai statis di dalamnya 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

Paku lain di peti mati

Terkadang dicoba untuk dibuktikan bahwa EOF adalah karakter dengan kode seperti ini:

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

Masalah dengan itu adalah bahwa datatype char bisa menjadi nilai yang ditandatangani atau tidak. Selain itu mereka adalah datatype terkecil yang membuatnya sangat berguna dalam mikrokontroler, di mana memori terbatas. Jadi, alih-alih mendeklarasikannya int foo = 25;, biasanya terlihat di mikrokontroler dengan memori kecil char foo = 25;atau yang serupa. Selain itu, karakter dapat ditandatangani atau tidak ditandatangani .

Orang dapat memverifikasi bahwa ukuran dalam byte dengan program seperti ini:

#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

Apa sebenarnya intinya? Intinya adalah bahwa EOF didefinisikan sebagai -1, tetapi char datatype dapat mencetak nilai integer .

BAIK . . jadi bagaimana jika kita mencoba mencetak char sebagai string?

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

Jelas kesalahan, tapi tetap saja, kesalahan akan memberi tahu kita sesuatu yang menarik:

skolodya @ ubuntu: $ gcc EOF.c -o EOF
EOF.c: Dalam fungsi 'main': EOF.c: 4: 5: peringatan: format '% s' mengharapkan argumen tipe 'char *', tetapi argumen 2 memiliki ketik 'int' [-Wformat =] printf ("% s", EOF);

Nilai hex

Mencetak EOF sebagai nilai hex memberi FFFFFFFF, nilai 16 bit (8 byte), pujian dua dari a -1.

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

Keluaran:

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

Hal aneh lain terjadi dengan kode berikut:

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

Jika satu menekan Shift+ A, kita mendapatkan nilai hex 41, jelas sama seperti pada tabel ASCII. Tetapi untuk Ctrl+ D, kami memiliki ffffffff, sekali lagi - nilai balik dari yang getchar()disimpan di 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

Rujuk ke bahasa lain

Perhatikan bahwa bahasa lain menghindari kebingungan ini, karena mereka beroperasi pada evaluasi status keluar fungsi, tidak membandingkannya dengan makro. Bagaimana cara membaca file di Java?

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

Bagaimana dengan python?

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

Poin hebat, memang suatu karakter dikirim entah bagaimana di beberapa titik.
kos

Saya pikir karakter EOF adalah sesuatu yang telah hilang dalam terjemahan, karena itu bukan karakter yang sebenarnya, tetapi EOT adalah karakter yang sebenarnya, ascii. Sosok pergi!
Sergiy Kolodyazhnyy

1
Jika Anda mencoba membaca dari /dev/null, itu harus mengembalikan EOF juga, kan? Atau apa yang saya dapatkan di sana?
Byte Commander

@ByteCommander mari kita cari tahu. Do cat / dev / null | kucing -A.
Sergiy Kolodyazhnyy

@ByteCommander menambahkan bagian yang membahas komentar Anda
Sergiy Kolodyazhnyy

2

EOF adalah singkatan dari end of file . Meskipun saya tidak tahu cara memicu simbol berikut, Anda dapat menjalankan program berikut melalui pemipaan file, yang mengirimkan sinyal EOF di akhir:

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

di mana a.outsumber kompilasi Anda


1
Sudah ter-upgrade, namun di samping EOF bukan karakter, saya pikir kesalahpahaman muncul dari fakta yang ditandai melalui penekanan tombol CTRL, yang biasanya merupakan cara untuk memasukkan karakter yang tidak dapat dicetak. Seperti yang saya mengerti semua yang sebenarnya terjadi adalah bahwa semua input memerah dan menjadi input untuk memerah kosong read()(syscall) akan kembali 0, yang ditafsirkan sebagai EOF: stackoverflow.com/a/1516177/4316166
kos

@kos, Anda benar, ini sinyal.
Paulius Šukys
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.