EOF nedir ve nasıl tetiklenir? [kapalı]


12

Bu benim C kaynak kodum.

Ubuntu'da oluşturduğumda, karakter almaya başlar, ancak programın nasıl sonlandırılacağını bilmiyorum, çünkü giriş ENTERveya bir satır başı ile bitmiyor .

EOF anlamı ne? Nasıl tetikleyebilirim?

Bu kaynak ayrıca Dennis Ritchie'nin bir kitabında:

#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
C dilinde -1EOF karşılığıdır. /usr/include/stdio.hMakro sabit olarak tanımlanır
Edward Torvalds


@edwardtorvalds girdi -1olarak giriyor çalışmıyor :)
Sergiy Kolodyazhnyy

Bence aynı Dennis Ritchie kitabı bunu açıklıyor.
andy256

Ayrıca ilgili: unix.stackexchange.com/questions/110240/… (Bu soruya gönderilen cevapların hiçbiri tamamen doğru değil.)
fkraiem

Yanıtlar:


23

Tl, Dr.

Son giriş yıkamasından hemen sonra CTRL+ Dtuş vuruşu olan bir terminalde çalışan bir programda genellikle EOF'u "tetikleyebilirsiniz" .


EOF anlamı ne? Nasıl tetikleyebilirim?

EOF Dosya Sonu anlamına gelir.

Bu durumda "EOF'un tetiklenmesi" kabaca "programın daha fazla giriş gönderilmeyeceğinin farkında olması" anlamına gelir.

Bu durumda, getchar()hiçbir karakter okunmazsa negatif bir sayı döndüreceğinden yürütme sonlandırılır.

Ancak bu sadece sizin özel programınız için değil, birçok farklı araç için de geçerlidir.

Genel olarak "tetikleme EOF" , son giriş sifonundan hemen sonra CTRL+ Dtuş vuruşu ile yapılabilir (yani boş bir giriş gönderilerek).

Örneğin cat:

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

CTRL+ Tuşuna basarken kaputun altında olan şey D, son giriş sifonundan bu yana yazılan girdinin yıkanmasıdır; bu boş bir girdi olduğunda read(), programın STDIN'inde çağrılan sistem çağrısı geri döner 0, getchar()negatif bir sayı döndürür ( -1GNU C kütüphanesinde) ve bu da EOF 1 olarak yorumlanır .


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


2
Derleme çalışır, çünkü virgül sınırlaması aynı satırda olmakla sınırlı değildir. Bunun dışında, EOF hakkında büyük açıklama :)
Paulius Šukys

@ PauliusŠukys Huh, haklısın. Benim C biraz paslı. :)
kos

1
iirc EOF olduğu değil olmak -1 standardına göre tanımlandığı gibidir. Örneğin glibc'de olan şey budur.
larkey


1
EOF 'bir "boş girdi" göndermekten ibaret değildir ve belirttiğiniz SO yanıtı aksini söylemez. Bant dışı bir sinyaldir. Terminal olması durumunda Ctrl / d yazılarak gönderilir.
user207421

4

TL; DR : EOF bir karakter değil, giriş okuma fonksiyonunun negatif dönüşünü değerlendirmek için kullanılan bir makro. Biri işlev döndürmeye zorlayacak karakter göndermek için Ctrl+ kullanabilirDEOT-1

Her programcı RTFM'ye sahip olmalıdır

Harbison ve Steele tarafından yayınlanan 4. CA Referans Kılavuzuna bakalım, 4. baskı. 1995, sayfa 317:

Negatif tamsayı EOF, "gerçek karakterin" kodlaması olmayan bir değerdir. . . Örneğin, fget (bölüm 15.6) dosya sonunda EOF değerini döndürür , çünkü okunacak "gerçek karakter" yoktur.

Esasen EOFbir karakter değil , temsil etmek için uygulanan bir tamsayı değerdir . Bu nedenle, kos'un cevabı olabildiğince doğrudur, ancak "boş" girdi almakla ilgili değildir. Önemli not, burada EOF, gerçek bir karakteri belirtmek için değil, dönüş değeri (of ) karşılaştırması olarak hizmet eder . Taşıyıcıların:stdio.h-1getchar()man getchar

GERİ DÖNÜŞ DEĞERİ

fgetc (), getc () ve getchar (), okunan karakteri dosya veya hata sonunda int veya EOF'ye imzasız bir char karakteri olarak döndürür.

gets () ve fgets () başarılı olduğunda döndürür ve hata durumunda veya hiçbir karakter okunmazken dosya sonu oluştuğunda NULL döndürür.

ungetc () başarı durumunda c'yi veya hata durumunda EOF değerini döndürür.

whileDöngüyü düşünün - birincil amacı, parantez içindeki durum doğruysa eylemi tekrarlamaktır . Tekrar bak:

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

Temelde c = getchar()başarılı kod döndürürse bir şeyler yapmaya devam et ( 0ya da yukarıda; bu arada yaygın bir şey, başarılı komut çalıştırmayı deneyin, echo $?sonra başarısız oldu echo $?ve döndükleri sayıları görün) diyor . Bu yüzden başarıyla karakter alırsak ve C'ye değer verirsek, döndürülen durum kodu 0, başarısız -1 olur. EOFolarak tanımlanır -1. Bu nedenle koşul -1 == -1oluştuğunda döngüler durur. Ve bu ne zaman olacak? Alınacak başka karakter olmadığında, c = getchar()başarısız olduğunda. Yazabilirsiniz while ((c = getchar ()) != -1)ve yine de işe yarardı

Ayrıca, gerçek koda geri dönelim, işte bir alıntı stdio.h

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

ASCII kodları ve EOT

EOF karakteri gerçek bir karakter olmamasına rağmen EOT, ASCII ondalık değeri 04 olan bir (İletim Sonu) karakteri vardır; Bu bağlantılıdır Ctrl+ D(meta karakter olarak da temsil kısayol ^D). İletim sonu karakteri, bilgisayarlar telefon bağlantılarını kontrol etmek için kullanıldığında bir veri akışının kapanışını, dolayısıyla "iletim sonu" adını belirtmek için kullanılır.

Bu nedenle, bu ascii değerini programa şu şekilde göndermek mümkündür, $'\04'hangisinin EOT olduğuna dikkat edin :

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

Böylece var olduğunu söyleyebiliriz, ancak yazdırılamaz

Kenar notu

Geçmiş bilgisayarlarda çok yönlü olmadığını sık sık unutuyoruz - tasarımcılar mevcut her klavye tuşunu kullanmak zorundalar. Bu nedenle, EOTCtrlD ile karakter gönderme, büyük harf A, ShiftA yazmanın aksine hala "bir karakter gönderir", yine de bilgisayara kullanılabilir tuşlarla bir giriş verirsiniz. Böylece EOT, kullanıcıdan geldiği anlamında gerçek bir karakterdir, bilgisayar tarafından okunabilir (yazdırılabilir olmasa da, insanlar tarafından görülemez), bilgisayar belleğinde bulunur

Byte Commander adlı kullanıcının yorumu

/ Dev / null'dan okumaya çalışırsanız, bu bir EOF da döndürmelidir, değil mi? Ya da oraya ne getireyim?

Evet, kesinlikle doğru, çünkü /dev/nullokunacak gerçek bir karakter yok, bu yüzden kodu c = getchar()döndürecek -1ve program hemen kapanacak. Yine komut EOF döndürmez. EOF, getchar fonksiyonunun dönüş kodunu karşılaştırmak için kullandığımız -1'e eşit sabit bir değişkendir . EOFkarakter olarak mevcut değil, içinde sadece statik bir değer var 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

Tabutta başka bir çivi

Bazen EOF'un böyle bir kodu olan bir karakter olduğu kanıtlanmaya çalışılır:

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

Sorun şu ki, char veri tipi imzalı veya imzasız bir değer olabilir. Ayrıca, hafızanın sınırlı olduğu mikrodenetleyicilerde onları çok kullanışlı kılan adreslenebilir en küçük veri tipidir. Bu nedenle, beyan int foo = 25;etmek yerine, küçük hafızaya char foo = 25;veya benzer bir şeye sahip mikrodenetleyicilerde görmek yaygındır . Ayrıca, karakter imzalı veya imzasız olabilir .

Aşağıdaki gibi bir programla bayt cinsinden boyut doğrulanabilir:

#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

Amaç tam olarak nedir? Mesele şu ki, EOF -1 olarak tanımlanmıştır, ancak char veri tipi tamsayı değerlerini yazdırabilir .

TAMAM . . .so char karakterlerini dize olarak yazdırmaya çalışırsak?

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

Açıkçası bir hata, ama yine de, hata bize ilginç bir şey söyleyecektir:

skolodya @ ubuntu: $ gcc EOF.c -o EOF
EOF.c: 'main' fonksiyonunda: EOF.c: 4: 5: uyarı: '% s' biçimi 'char *' türünde bir argüman bekliyor, ancak 2 argümanı 'int' [-Wformat =] printf ("% s", EOF) yazın;

Onaltılı değerler

EOF'u onaltılık değer olarak yazdırmak FFFFFFFF, 16 bit (8 bayt) bir değer verir, ikisinin a -1.

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

Çıktı:

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

Başka bir meraklı şey aşağıdaki kodla gerçekleşir:

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

Biri Shift+ tuşuna basarsa A, ASCII tablosunda olduğu gibi onaltılık 41 değerini alırız. Ama Ctrl+ Diçin ffffffff, yine - içinde getchar()depolanan dönüş değerine sahibiz 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

Diğer dillere bakın

Diğer dilin bu karışıklığı önlediğine dikkat edin, çünkü bir işlev çıkış durumunu değerlendirmekle çalışırlar, bir makro ile karşılaştırmazlar. Java ile dosya nasıl okunur?

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

Python'a ne dersin?

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

Harika bir nokta, bir karakter gerçekten bir şekilde bir noktada gönderiliyor.
kos

Bence EOF karakteri çeviride kaybolmuş bir şey, çünkü gerçek bir karakter değil, ama EOT gerçek, ascii bir karakter. Git şekil!
Sergiy Kolodyazhnyy

1
Eğer okumaya çalışırsanız /dev/null, bu da bir EOF döndürmelidir, değil mi? Ya da oraya ne getireyim?
Bayt Komutanı

@ByteCommander öğrenelim. Kedi / dev / null yap | kedi -A.
Sergiy Kolodyazhnyy

@ByteCommander yorumunuzu adresleyen bölüm ekledi
Sergiy Kolodyazhnyy

2

EOF , dosya sonu anlamına gelir . Aşağıdaki sembolü nasıl tetikleyeceğimi bilmesem de, sonunda EOF sinyalini gönderen bir dosyayı borulandırarak aşağıdaki programı çalıştırabilirsiniz :

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

a.outderlenmiş kaynağın nerede


1
Bunu zaten seçmiştim, ancak bir yan notta EOF bir karakter değil, yanlış anlama, genellikle yazdırılamayan karakterleri girmenin bir yolu olan bir CTRL tuş vuruşu ile bildirilen gerçeğinden kaynaklanıyor. Aslında tüm bunların gerçekleştiğini anladığım gibi, tüm girdiler temizlendi ve boşaltılacak girişin boş olduğu read()(sistem çağrısı) geri dönecek 0, ki bu EOF olarak yorumlandı: stackoverflow.com/a/1516177/4316166
kos

@kos, Haklısın, bu bir sinyalden sonra bir sinyal.
Paulius Šukys
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.