什么是EOF以及如何触发?[关闭]


12

这是我的C源代码。

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

EOF是什么意思?我该如何触发呢?

丹尼斯·里奇(Dennis Ritchie)的书中也有此消息来源:

#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语言-1中的EOF等效于EOF。它定义/usr/include/stdio.h为宏常量
Edward Torvalds,2016年


@edwardtorvalds输入-1为输入不起作用:)
Sergiy Kolodyazhnyy 2016年

我认为同一本丹尼斯·里奇(Dennis Ritchie)的书也解释了这一点。
andy256 '16

也相关:unix.stackexchange.com/questions/110240/…(此问题的答案均​​不完全正确。)
fkraiem

Answers:


22

l

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


EOF是什么意思?我该如何触发呢?

EOF表示文件结束。

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

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

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

通常,可以在最后一次输入刷新后立即通过CTRL+ D按键(即通过发送空输入)来进行“触发EOF” 。

例如cat

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

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


1- /programming//a/1516177/4316166


2
编译有效,因为逗号分隔不受同一行的限制。除此之外,对EOF的解释也不错:)
PauliusŠukys'16

@PauliusŠukysHuh,您是对的。我的C有点生锈。:)
kos

1
根据标准,iirc EOF 未被定义为-1。例如,这正是glibc中的情况。
larkey


1
EOF不会“包含发送“空输入””,您引用的SO答案也不会相反。这是一个带外信号。对于终端,通过键入Ctrl / d发送。
user207421 '16

4

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

每个程序员都必须RTFM

让我们参考Harbison和Steele,第4版的“ CA参考手册”。从1995年开始,第317页:

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

本质EOF上不是字符,而是实现为表示的整数。因此,kos的答案就目前而言是正确的,但这与接收“空”输入无关。重要说明的是,这里EOF作为返回值(中)比较,不表示实际的字符。该支架是:stdio.h-1getchar()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

很重要的一点是,确实有人在某个时候发送了角色。
kos

我认为EOF字符是翻译中丢失的东西,因为它不是实际字符,但EOT是实际的ascii字符。去搞清楚 !
Sergiy Kolodyazhnyy

1
如果您尝试从阅读/dev/null,那也应该返回EOF,对吗?还是我能到达那里?
字节指挥官

@ByteCommander让我们找出答案。做cat / dev / null | 猫-A。
Sergiy Kolodyazhnyy

@ByteCommander添加了解决您的评论的部分
Sergiy Kolodyazhnyy 2016年

2

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

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

a.out您的编译源在哪里


1
已经对此提出了支持,但是从侧面说明EOF不是字符,我认为误解是由于通过CTRL按键发出信号这一事实而引起的,这通常是输入不可打印字符的方式。据我了解,实际发生的一切是所有输入均已刷新,并且将被清空的输入read()(syscall)将返回0,这被解释为EOF:stackoverflow.com/a/1516177/4316166
kos

@kos,你是对的,毕竟这是一个信号。
PauliusŠukys,2016年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.