TL; DR : EOF nie jest znakiem, to makro używane do oceny ujemnego zwrotu funkcji odczytu danych wejściowych. Można użyć Ctrl+, Daby wysłać EOT
znak, który wymusi powrót funkcji-1
Każdy programista musi RTFM
Odwołajmy się do „CA Reference Manual” Harbison i Steele, wydanie 4. od 1995 r., strona 317:
Ujemna liczba całkowita EOF to wartość, która nie jest kodowaniem „prawdziwego znaku”. . . Na przykład fget (sekcja 15.6) zwraca EOF na końcu pliku, ponieważ nie ma „prawdziwego znaku” do odczytania.
Zasadniczo EOF
nie jest postacią, ale raczej liczbą całkowitą zaimplementowaną stdio.h
do reprezentowania -1
. Tak więc odpowiedź kos jest poprawna, ale nie chodzi o otrzymywanie „pustych” danych wejściowych. Ważna uwaga jest taka, że tutaj EOF służy jako wartości zwracanej (z getchar()
) stosunku, aby nie oznaczać rzeczywistego charakteru. Na man getchar
podpory, że:
WARTOŚĆ ZWRACANA
fgetc (), getc () i getchar () zwracają znak odczytany jako rzut bez znaku do int lub EOF na końcu pliku lub błędu.
gets () i fgets () zwracają s w przypadku powodzenia, a NULL w przypadku błędu lub gdy nastąpi koniec pliku, gdy nie zostały odczytane żadne znaki.
ungetc () zwraca c w przypadku sukcesu lub EOF w przypadku błędu.
Rozważmy while
pętlę - jej podstawowym celem jest powtórzenie akcji, jeśli warunek w nawiasach jest spełniony . Spójrz ponownie:
while ((c = getchar ()) != EOF)
Zasadniczo mówi: kontynuuj robienie rzeczy, jeśli c = getchar()
zwróci udany kod ( 0
lub wyższy; przy okazji, spróbuj wykonać udane polecenie, echo $?
a potem się nie powiedzie echo $?
i zobacz liczby, które zwracają). Więc jeśli uda nam się uzyskać znak i przydzielić C, zwrócony kod stanu to 0, błąd to -1. EOF
jest zdefiniowany jako -1
. Dlatego gdy -1 == -1
wystąpi warunek , pętle zatrzymują się. A kiedy to się stanie? Gdy nie ma już postaci do zdobycia, gdy się c = getchar()
nie powiedzie. Możesz pisać while ((c = getchar ()) != -1)
i nadal będzie działać
Wróćmy też do samego kodu, oto fragment stdio.h
/* End of file character.
Some things throughout the library rely on this being -1. */
#ifndef EOF
# define EOF (-1)
#endif
Kody ASCII i EOT
Chociaż znak EOF nie jest znakiem rzeczywistym, istnieje EOT
znak (End of Transmission), który ma wartość dziesiętną ASCII 04; jest połączony ze skrótem Ctrl+ D(reprezentowanym również jako znak meta ^D
). Znak końca transmisji używany do oznaczania zamknięcia strumienia danych z powrotem, gdy komputery były używane do kontrolowania połączeń telefonicznych, stąd nazewnictwo „koniec transmisji”.
Możliwe jest przesłanie takiej wartości ascii do programu w ten sposób, zwróć uwagę na $'\04'
to, co jest 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
Możemy zatem powiedzieć, że istnieje, ale nie można go wydrukować
Dygresja
Często zapominamy, że w przeszłości komputery nie były tak wszechstronne - projektanci musieli korzystać z każdego dostępnego klawisza klawiatury. Tak więc, wysyłanie EOT
znaku za pomocą CtrlD nadal „wysyła znak”, podobnie jak pisanie wielką literą A, ShiftA, nadal dajesz komputerowi wejście z dostępnymi kluczami. Zatem EOT jest prawdziwą postacią w tym sensie, że pochodzi od użytkownika, jest czytelny dla komputera (choć nie do wydrukowania, niewidoczny dla ludzi), istnieje w pamięci komputera
Komentarz Byte Commander
Jeśli spróbujesz czytać z / dev / null, powinno to również zwrócić EOF, prawda? A co tam dostanę?
Tak, dokładnie tak, ponieważ /dev/null
nie ma żadnego rzeczywistego znaku do odczytania, dlatego c = getchar()
zwróci -1
kod, a program natychmiast zakończy działanie. Ponownie polecenie nie zwraca EOF. EOF to tylko stała zmienna równa -1, której używamy do porównywania kodu powrotu funkcji getchar . EOF
nie istnieje jako postać, jest tylko wartością statyczną w środku stdio.h
.
Próbny:
# 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
Kolejny gwóźdź do trumny
Czasami próbuje się udowodnić, że EOF jest znakiem o takim kodzie:
#include <stdio.h>
int main(void)
{
printf("%c", EOF);
return 0;
}
Problem w tym, że typ danych char może być wartością podpisaną lub niepodpisaną. Ponadto są najmniejszymi adresowalnymi typami danych, co czyni je bardzo przydatnymi w mikrokontrolerach, w których pamięć jest ograniczona. Zamiast deklarować int foo = 25;
, często obserwuje się w mikrokontrolerach z małą pamięcią char foo = 25;
lub czymś podobnym. Ponadto znaki mogą być podpisane lub niepodpisane .
Można sprawdzić, czy rozmiar w bajtach za pomocą takiego programu:
#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
O co dokładnie chodzi? Chodzi o to, że EOF jest zdefiniowany jako -1, ale typ danych char może wydrukować wartości całkowite .
OK . . . więc co, jeśli spróbujemy wydrukować znak jako ciąg?
#include <stdio.h>
int main(void)
{
printf("%s", EOF);
return 0;
}
Oczywiście błąd, ale błąd powie nam coś ciekawego:
skolodya @ ubuntu: $ gcc EOF.c -o EOF
EOF.c: W funkcji „main”: EOF.c: 4: 5: ostrzeżenie: format „% s” oczekuje argumentu typu „char *”, ale argument 2 ma wpisz „int”
[-Wformat =] printf („% s”, EOF);
Wartości szesnastkowe
Drukowanie EOF jako wartości szesnastkowej daje FFFFFFFF
16-bitową (8-bajtową) wartość, komplement dwóch z a -1
.
#include <stdio.h>
int main(void)
{
printf("This is EOF: %X\n", EOF);
printf("This is Z: %X\n",'Z');
return 0;
}
Wynik:
DIR:/xieerqi
skolodya@ubuntu:$ ./EOF
This is EOF: FFFFFFFF
This is Z: 5A
Następująca ciekawa rzecz występuje z następującym kodem:
#include <stdio.h>
int main(void)
{
char c;
if (c = getchar())
printf ("%x",c);
return 0;
}
Jeśli naciśniesz Shift+ A, otrzymamy wartość szesnastkową 41, oczywiście taką samą jak w tabeli ASCII. Ale dla Ctrl+ Dmamy ffffffff
ponownie wartość zwracaną getchar()
przechowywaną w 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
Zobacz inne języki
Zauważ, że inne języki unikają tego zamieszania, ponieważ działają na ocenie stanu wyjścia funkcji, a nie na porównaniu z makrem. Jak można odczytać plik w Javie?
File inputFile = new File (filename);
Scanner readFile = new Scanner(inputFile);
while (readFile.hasNext())
{ //more code bellow }
Co powiesz na python?
with open("/etc/passwd") as file:
for line in file:
print line
-1
jest równoważne EOF. Jest zdefiniowany/usr/include/stdio.h
jako stała makro