TL; DR:EOF不是字符,它是用于评估输入读取功能的负返回的宏。一个可以使用Ctrl+ D发送EOT
字符,这将强制函数返回-1
每个程序员都必须RTFM
让我们参考Harbison和Steele,第4版的“ CA参考手册”。从1995年开始,第317页:
负整数EOF是一个不是“实字符”编码的值。。。例如,fget(第15.6节)在文件结尾时返回EOF,因为没有要读取的“真实字符”。
本质EOF
上不是字符,而是实现为表示的整数。因此,kos的答案就目前而言是正确的,但这与接收“空”输入无关。重要说明的是,这里EOF作为返回值(中)比较,不表示实际的字符。该支架是:stdio.h
-1
getchar()
man getchar
返回值
fgetc(),getc()和getchar()返回以无符号字符形式读取的字符,在文件或错误结束时将其转换为int或EOF。
gets()和fgets()成功返回s,错误或在未读取任何字符的情况下出现文件结尾时返回NULL。
ungetc()成功返回c,错误返回EOF。
考虑while
循环-它的主要目的是在括号中的条件为true时重复执行操作。再看一遍:
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;该字符为ASCII码。它链接到Ctrl+ D快捷方式(也表示为meta字符^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
因此,我们可以说它确实存在,但不可打印
边注
我们常常会忘记过去的计算机不那么通用-设计人员必须利用所有可用的键盘键。因此,EOT
使用CtrlD 发送字符仍然是“发送字符”,与键入大写字母A,ShiftA有所不同,您仍然需要为计算机提供可用键的输入。因此,从某种意义上讲,EOT确实是真实的字符,它确实来自用户,它可以被计算机读取(尽管不可打印,人类看不见),它存在于计算机内存中
字节指挥官的评论
如果您尝试从/ 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<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
棺材上的另一个钉子
有时试图证明EOF是具有如下代码的字符:
#include <stdio.h>
int main(void)
{
printf("%c", EOF);
return 0;
}
问题在于char数据类型可以是有符号或无符号的值。此外,它们是最小的可寻址数据类型,这使得它们在内存有限的微控制器中非常有用。因此,不用声明int foo = 25;
通常会在内存较小char foo = 25;
或类似的微控制器中看到它。另外,字符可以是签名的也可以是未签名的。
可以使用以下程序验证字节大小:
#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
到底是什么意思?关键是EOF定义为-1,但是char数据类型可以打印整数值。
好 。。.so如果我们尝试将char打印为字符串怎么办?
#include <stdio.h>
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);
十六进制值
将EOF打印为十六进制值可得到FFFFFFFF
一个16位(8字节)值,即a的二进制补码-1
。
#include <stdio.h>
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 <stdio.h>
int main(void)
{
char c;
if (c = getchar())
printf ("%x",c);
return 0;
}
如果按Shift+ A,我们将得到十六进制值41,显然与ASCII表中的相同。但是对于Ctrl+来说D,我们ffffffff
又有- getchar()
存储在中的返回值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
参考其他语言
请注意,其他语言避免了这种混淆,因为它们用于评估函数退出状态,而不是将其与宏进行比较。如何用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
-1
中的EOF等效于EOF。它定义/usr/include/stdio.h
为宏常量