什么是EOF以及如何触发它?

这是我的C源代码。

当我在Ubuntu中构建它时,它开始获取字符,但我不知道如何结束程序,因为它不会通过输入ENTER或回车来结束。

EOF是什么意思? 我怎么能触发它?

这个消息来源也在Dennis Ritchie的一本书上:

#include  /* count digits, white space, others */ main () { int c, i, nwhite, nother; int ndigit[10]; nwhite = nother = 0; for (i = 0; i = '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); } 

文艺青年最爱的

在最后一次输入刷新之后,通常可以在终端中运行的程序中使用CTRL + D键击“触发EOF”。


EOF是什么意思? 我怎么能触发它?

EOF表示文件结束。

在这种情况下,“触发EOF”大致意味着“使程序意识到不再发送输入”。

在这种情况下,如果没有读取字符,则getchar()将返回负数,因此终止执行。

但这不仅适用于您的特定程序,它适用于许多不同的工具。

通常,“触发EOF”可以在最后一次输入刷新之后用CTRL + D键击完成(即通过发送空输入)。

例如用cat

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

当按下CTRL + D时发生的事情是,自上次输入刷新后输入的输入被刷新; 当这恰好是一个空输入时,在程序的STDIN上调用的read()系统调用返回0getchar()返回一个负数(在GNU C库中为-1 ),而这又被解释为EOF 1


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

TL; DR :EOF不是字符,它是用于评估输入读取函数的负返回的宏。 可以使用Ctrl + D发送EOT字符,这将强制函数返回-1

每个程序员都必须RTFM

让我们参考Harbison和Steele撰写的“CA Reference Manual”,第4版。 从1995年,第317页:

负整数EOF是不是“真实字符”的编码的值。 。 。 例如,fget(第15.6节)在文件结束时返回EOF ,因为没有要读取的“真实字符”。

基本上EOF不是一个字符,而是一个在stdio.h实现的整数值来表示-1 。 因此,就这一点而言,kos的答案是正确的,但它不是关于接收“空”输入。 重要的是,这里EOF用作( getchar() )比较的返回值 ,而不是表示实际的字符。 man getchar支持:

返回值

fgetc(),getc()和getchar()将读取的字符作为unsigned char强制转换为文件末尾或错误的int或EOF。

gets()和fgets()在成功时返回s,在出错时或在文件结束时没有读取任何字符时返回NULL。

ungetc()在成功时返回c,或在出错时返回EOF。

考虑while循环 – 其主要目的是在括号中的条件为真时重复操作。 再看一遍:

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

它基本上说如果c = getchar()返回成功代码( 0或更高;顺便说一下,尝试运行成功命令,然后echo $?然后失败echo $?并查看返回的数字),继续做东西。 因此,如果我们成功获得字符并向C求助,则返回的状态代码为0,失败为-1。 EOF定义为-1 。 因此,当条件-1 == -1发生时,循环停止。 什么时候会发生? 当没有更多的字符可以获得时,当c = getchar()失败时。 你可以写while ((c = getchar ()) != -1)它仍然可以工作

另外,让我们回到实际的代码,这里是stdio.h的摘录

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

ASCII码和EOT

虽然EOF字符不是实际字符,但是存在EOT (传输结束)字符,其ASCII十进制值为04; 它链接到Ctrl + D快捷键(也表示为元字符^D )。 当计算机用于控制电话连接时,传输结束用于表示数据流的关闭,因此“传输结束”命名。

所以可以像这样将ascii值发送给程序,注意$'\04'这是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 

因此,我们可以说它确实存在,但它不可打印

边注

我们经常忘记过去的计算机不是那么通用 - 设计师必须使用每个键盘键。 因此,使用CtrlD发送EOT字符仍然是“发送字符”,与输入大写字母A,ShiftA不同,您仍然可以使用可用密钥为计算机提供输入。 因此EOT是一个真正的角色,它确实来自用户,它可以被计算机读取(虽然不可打印,人类不可见),它存在于计算机内存中

Byte Commander的评论

如果你试图从/ dev / null读取,那也应该返回一个EOF,对吗? 或者我到那里去了什么?

是的,完全正确,因为在/dev/null中没有要读取的实际字符,因此c = getchar()将返回-1代码,程序将立即退出。 再次命令不返回EOF。 EOF只是常量变量等于-1,我们用它来比较getchar函数的返回码EOF不作为字符存在,它只是stdio.h的静态值。

演示:

 # 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 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 

棺材里的另一个钉子

有时会尝试certificateEOF是一个代码如下的字符:

 #include  int main(void) { printf("%c", EOF); return 0; } 

问题是char数据类型可以是有符号或无符号值。 此外,它们是最小的可寻址数据类型,这使得它们在内存有限的微控制器中非常有用。 因此,而不是声明int foo = 25; 在具有小内存的微控制器中看到char foo = 25; 或类似的东西。 此外, 字符可以是签名的或未签名的 。

可以使用如下程序validation大小(以字节为单位):

 #include  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 

究竟是什么意思? 关键是EOF定义为-1,但char数据类型可以打印整数值

好 。 。 那么如果我们尝试将char打印为字符串呢?

 #include  int main(void) { printf("%s", EOF); return 0; } 

显然是一个错误,但是,错误会告诉我们一些有趣的事情:

skolodya @ ubuntu:$ gcc EOF.c -o EOF
EOF.c:在函数'main'中:EOF.c:4:5:警告:格式'%s'需要类型'char *'的参数但参数2的类型为'int' [-Wformat =] printf(“ %s“,EOF);

hex值

将EOF作为hex值打印给出FFFFFFFF ,一个16位(8字节)值,两个对-1

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

输出:

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

使用以下代码会发生另一个奇怪的事情:

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

如果按Shift + A ,我们得到hex值41,显然与ASCII表中相同。 但是对于Ctrl + D ,我们再次使用ffffffff - 存储在cgetchar()的返回值。

 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 

请参阅其他语言

请注意,其他语言避免了这种混淆,因为它们在评估函数退出状态时运行,而不是将其与宏进行比较。 如何用Java读取文件?

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

python怎么样?

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

EOF代表文件结尾 。 虽然我不知道如何触发以下符号,但您可以通过管道文件运行以下程序,该文件最后发送EOF信号:

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

其中a.out是您的编译源