TL; DR : EOF không phải là một ký tự, nó là một macro được sử dụng để đánh giá lợi nhuận âm của chức năng đọc đầu vào. Người ta có thể sử dụng Ctrl+ Dđể gửi EOT
ký tự sẽ buộc hàm trả về-1
Mọi lập trình viên đều phải RTFM
Hãy để chúng tôi tham khảo "Hướng dẫn tham khảo CA" của Harbison và Steele, tái bản lần thứ 4. từ năm 1995, trang 317:
Số nguyên âm EOF là một giá trị không phải là mã hóa của "ký tự thực". . . Ví dụ: fget (phần 15.6) trả về EOF khi ở cuối tệp, vì không có "ký tự thực" nào được đọc.
Về cơ bản EOF
không phải là một ký tự, mà là một giá trị nguyên được triển khai stdio.h
để thể hiện -1
. Do đó, câu trả lời của kos là chính xác cho đến nay, nhưng đó không phải là về việc nhận đầu vào "trống". Lưu ý quan trọng là ở đây EOF đóng vai trò so sánh giá trị trả về (của getchar()
), không biểu thị một ký tự thực tế. Các man getchar
hỗ trợ đó:
GIÁ TRỊ TRẢ LẠI
fgetc (), getc () và getchar () trả về ký tự được đọc dưới dạng char không dấu cho một int hoặc EOF ở cuối tệp hoặc lỗi.
được () và fgets () trả về s thành công và NULL bị lỗi hoặc khi kết thúc tệp xảy ra trong khi không có ký tự nào được đọc.
ungetc () trả về c khi thành công hoặc EOF bị lỗi.
Xem xét while
vòng lặp - mục đích chính của nó là lặp lại hành động nếu điều kiện trong ngoặc là đúng . Nhìn lại:
while ((c = getchar ()) != EOF)
Về cơ bản, nó nói rằng hãy tiếp tục làm công cụ nếu c = getchar()
trả về mã thành công ( 0
hoặc cao hơn; đó là một điều phổ biến, hãy thử chạy lệnh thành công, sau echo $?
đó thất bại echo $?
và xem số chúng trả về). Vì vậy, nếu chúng tôi nhận được ký tự và xác nhận thành công C, mã trạng thái được trả về là 0, không thành công là -1. EOF
được định nghĩa là -1
. Do đó khi điều kiện -1 == -1
xảy ra, các vòng lặp dừng lại. Và khi nào thì điều đó sẽ xảy ra? Khi không còn nhân vật để nhận, khi c = getchar()
thất bại. Bạn có thể viết while ((c = getchar ()) != -1)
và nó vẫn hoạt động
Ngoài ra, hãy quay trở lại mã thực tế, đây là một đoạn trích từ stdio.h
/* End of file character.
Some things throughout the library rely on this being -1. */
#ifndef EOF
# define EOF (-1)
#endif
Mã ASCII và EOT
Mặc dù ký tự EOF không phải là ký tự thực tế, tuy nhiên, vẫn tồn tại EOT
ký tự (Kết thúc truyền), có giá trị thập phân ASCII là 04; nó được liên kết với Ctrl+ Dphím tắt (cũng được biểu thị dưới dạng ký tự meta ^D
). Sự kết thúc của bộ truyền phát được sử dụng để biểu thị việc đóng một luồng dữ liệu trở lại khi máy tính được sử dụng để kiểm soát các kết nối điện thoại, do đó đặt tên là "kết thúc truyền".
Vì vậy, có thể gửi giá trị ascii đó cho chương trình như vậy, lưu ý $'\04'
đó 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
Vì vậy, chúng ta có thể nói rằng nó tồn tại, nhưng nó không thể in được
Lưu ý bên
Chúng ta thường quên rằng trước đây các máy tính không linh hoạt - các nhà thiết kế phải sử dụng mọi phím bàn phím có sẵn. Do đó, việc gửi EOT
ký tự bằng CtrlD vẫn là "gửi một ký tự", không giống như gõ vốn A, ShiftA, bạn vẫn tạo cho máy tính một đầu vào với các phím khả dụng. Do đó, EOT là một nhân vật thực sự theo nghĩa là nó đến từ người dùng, nó có thể đọc được bằng máy tính (mặc dù không thể in được, không thể nhìn thấy bởi con người), nó tồn tại trong bộ nhớ máy tính
Nhận xét của Byte Commander
Nếu bạn cố đọc từ / dev / null, điều đó cũng sẽ trả về EOF, phải không? Hay tôi đến đó bằng gì?
Vâng, chính xác là đúng, bởi vì /dev/null
không có ký tự thực tế nào được đọc, do đó nó c = getchar()
sẽ trả về -1
mã và chương trình sẽ thoát ngay lập tức. Một lần nữa lệnh không trả về EOF. EOF chỉ là biến không đổi bằng -1, mà chúng ta sử dụng để so sánh mã trả về của hàm getchar . EOF
không tồn tại như một nhân vật, nó chỉ là một giá trị tĩnh bên trong stdio.h
.
Bản giới thiệu:
# 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
Một cái đinh khác trong quan tài
Đôi khi người ta cố chứng minh rằng EOF là một ký tự có mã như thế này:
#include <stdio.h>
int main(void)
{
printf("%c", EOF);
return 0;
}
Vấn đề với đó là kiểu dữ liệu char có thể là một giá trị được ký hoặc không dấu. Ngoài ra, chúng là kiểu dữ liệu địa chỉ nhỏ nhất khiến chúng rất hữu ích trong các bộ vi điều khiển, nơi bộ nhớ bị hạn chế. Vì vậy, thay vì khai báo int foo = 25;
, người ta thường thấy trong các bộ vi điều khiển có bộ nhớ nhỏ char foo = 25;
hoặc một cái gì đó tương tự. Ngoài ra, ký tự có thể được ký hoặc không dấu .
Người ta có thể xác minh rằng kích thước tính theo byte với một chương trình như thế này:
#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
Chính xác thì điểm là gì? Điểm đáng chú ý là EOF được định nghĩa là -1, nhưng kiểu dữ liệu char có thể in các giá trị nguyên .
ĐỒNG Ý . . Nếu chúng ta thử in char dưới dạng chuỗi thì sao?
#include <stdio.h>
int main(void)
{
printf("%s", EOF);
return 0;
}
Rõ ràng là một lỗi, nhưng dù sao, lỗi sẽ cho chúng ta biết một điều thú vị:
skolodya @ ubfox: $ gcc EOF.c -o EOF
EOF.c: Trong chức năng 'main': EOF.c: 4: 5: cảnh báo: định dạng '% s' mong đợi đối số của loại 'char *', nhưng đối số 2 có gõ 'int'
[-Wformat =] printf ("% s", EOF);
Giá trị hex
In EOF dưới dạng giá trị hex sẽ cho giá trị FFFFFFFF
16 bit (8 byte), hai lời khen của a -1
.
#include <stdio.h>
int main(void)
{
printf("This is EOF: %X\n", EOF);
printf("This is Z: %X\n",'Z');
return 0;
}
Đầu ra:
DIR:/xieerqi
skolodya@ubuntu:$ ./EOF
This is EOF: FFFFFFFF
This is Z: 5A
Một điều tò mò khác xảy ra với đoạn mã sau:
#include <stdio.h>
int main(void)
{
char c;
if (c = getchar())
printf ("%x",c);
return 0;
}
Nếu một lần nhấn Shift+ A, chúng ta sẽ nhận được giá trị hex 41, rõ ràng giống như trong bảng ASCII. Nhưng đối với Ctrl+ D, chúng ta có ffffffff
, một lần nữa - giá trị trả về của getchar()
được lưu trữ trong 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
Tham khảo các ngôn ngữ khác
Lưu ý rằng ngôn ngữ khác tránh sự nhầm lẫn này, bởi vì chúng hoạt động để đánh giá trạng thái thoát hàm, không so sánh nó với macro. Làm thế nào để một người đọc tệp trong Java?
File inputFile = new File (filename);
Scanner readFile = new Scanner(inputFile);
while (readFile.hasNext())
{ //more code bellow }
Còn trăn thì sao?
with open("/etc/passwd") as file:
for line in file:
print line
-1
tương đương với EOF. Nó được định nghĩa/usr/include/stdio.h
là một hằng số vĩ mô