在 C 代码中表示 EOF?

Representing EOF in C code?

提问人:static_rtti 提问时间:9/12/2012 更新时间:12/18/2020 访问量:168068

问:

换行符在 C 代码中表示。文件结尾 (EOF) 字符是否有等效项?"\n"

C 字符 ASCII EOF

评论

21赞 Kerrek SB 9/12/2012
这个问题错误地假定“EOF”是一个字符,而实际上它是一个条件。事实上,如果它是一个角色,它就不再是结局了,不是吗?
2赞 wildplasser 9/12/2012
没有 EOF 字符。EOF 是用于指示 EOF 条件的越界值。它不等于任何字符值(由 getc() et.al 读取。
5赞 Paul R 9/12/2012
@Kerrek SB:你是对的,但请注意,过去的一些操作系统实际上确实有一个嵌入在文件中的EOF字符,例如CP / M为此使用了Control-Z。
3赞 Rich Lysakowski PhD 1/13/2022
像“问题'太明显'了”这样的问题不如表现出善意和给予指导的答案有用。这个关于 EOF 和 SOF 的问题一直困扰着我,直到我深入研究它。这是一篇很好的文章,它讨论了这个确切的观点,并通过代码示例更详细地回答了它......ruslanspivak.com/eofnotchar

答:

108赞 Paul R 9/12/2012 #1

EOF 不是一个字符(在大多数现代操作系统中)。它只是在到达文件流的末尾时应用于文件流的条件。之所以出现混淆,是因为用户可以通过键入特殊字符(例如 Unix、Linux 中的 Control-D)来向控制台输入发出 EOF 信号,但该字符不会被正在运行的程序看到,它作系统捕获,而操作系统又会向进程发出 EOF 信号。

注意:在一些非常古老的操作系统中,EOF是一个字符,例如CP / M中的Control-Z,但这是一个粗略的黑客,以避免在文件系统目录中维护实际文件长度的开销。

评论

3赞 Eric Postpischil 9/12/2012
C 标准不保证 EOF 不是字符。
3赞 Jonathan Leffler 9/12/2012
@EricPostpischil:C 标准确实(间接地)保证 et al 的返回值要么是有效字符,要么是不同的代码 EOF,而不是有效字符的代码。EOF 扩展为整数常量表达式,类型为 int 和负值,由多个函数返回以指示文件结束,即不再有来自流的输入;和“FGETC 函数获取 [下一个] 字符作为转换为 int无符号字符”。因此,在任何系统上,EOF 都不同于任何 .getchar()sizeof(char) != sizeof(int)char
11赞 Michael Burr 9/13/2012
另请注意,即使在今天 Windows 中,如果文件以文本模式打开,文件中的 Ctrl-Z 也会触发 EOF 条件。Microsoft非常重视它们与CP / M的向后兼容性。
2赞 Ben Voigt 8/2/2014
@MichaelBurr:您确定这是 Windows 而不是特定于编译器的 stdio 实现吗?AFAIK,Windows 甚至没有“以文本模式打开”条件。
2赞 Ben Voigt 5/22/2018
@vercellop:是的,命令解释器有很多DOS向后兼容性。但是,虽然它与 Windows 捆绑在一起,但它只是一个用户模式工具,而不是操作系统的一部分。
1赞 onoma 9/12/2012 #2

这依赖于系统,但通常是 -1。看这里

0赞 Lundin 9/12/2012 #3

有一个 int 类型的常量,可在 stdio.h 中找到。任何标准都没有指定的等效字符文本。EOF

11赞 pmakholm 9/12/2012 #4

不。EOF 不是字符,而是文件句柄的状态。

虽然 ASCII 字符集中有一些控制字符表示数据的结束,但这些字符通常不用于表示文件的结束。例如,EOT (^D),在某些情况下,它几乎发出相同的信号。

当标准 C 库使用有符号整数返回字符并使用 -1 作为文件末尾时,这实际上只是指示发生错误的信号。我没有可用的 C 标准,但引用 SUSv3:

如果设置了流的文件结束指示器,或者如果流处于文件末尾,则应设置流的文件结束指示器,并且 fgetc() 应返回 EOF。如果发生读取错误,则应设置流的错误指示器,fgetc() 将返回 EOF,并应设置 errno 以指示错误。

1赞 Keith Miller 9/12/2012 #5

我认为它可能因系统而异,但检查的一种方法是仅使用printf

#include <stdio.h>
int main(void)
{
    printf("%d", EOF);
    return 0;
}

我在 Windows 上执行了此操作并打印到控制台。希望这会有所帮助。-1

评论

0赞 Koray Tugay 6/7/2015
如果 eof 是一个字符,为什么用 %d 打印?
16赞 aib 9/12/2012 #6

EOF不是一个字符。它不能是:(二进制)文件可以包含任何字符。假设您有一个字节不断增加的文件,即 0 1 2 3 ...255 再次 0 1 ...255,总共 512 个字节。无论您认为这 256 个可能的字节中的哪一个,文件都会被剪短。EOF

这就是为什么 et al. 返回一个 .可能的返回值的范围是 a 可以具有的值,加上一个真正的值(在 中定义)。这也是为什么在检查之前将返回值转换为 a 不起作用的原因。getchar()intcharintEOFstdio.hcharEOF

请注意,某些协议具有“EOF”“字符”。ASCII 有“文本结束”、“传输结束”、“传输块结束”和“媒体结束”。其他答案提到了旧的操作系统。我自己在 Linux 上输入 ^D,在 Windows 控制台上输入 ^Z 以停止提供程序输入。(但是通过管道读取的文件可以在任何地方使用 ^D 和 ^Z 字符,并且只有在字节用完时才会发出 EOF 信号。C 字符串以字符结尾,但这也意味着它们不能包含字符 .这就是为什么所有 C 非字符串数据函数都使用数组(包含数据)和 a(知道数据结束的位置)工作。'\0''\0'charsize_t

编辑:C99标准§7.19.1.3规定:

宏是 [...]
EOF
扩展为具有类型和负值的整数常量表达式,由多个函数返回给 表示文件末尾,即不再有来自流的输入;
int

评论

0赞 Eric Postpischil 9/12/2012
C 标准不保证 EOF 不是字符。
1赞 Eric Postpischil 9/13/2012
您的编辑未显示 EOF 不等于字符值。EOF 指示文件末尾这一事实并不妨碍它等于 char 值。EOF 为负数这一事实并不妨碍它等于 char 值。(允许 EOF 作为字符值是一件令人讨厌的事情,但作为我链接到状态的答案,并不排除 C 实现符合 C 标准。
1赞 aib 9/13/2012
这并不能改变问题。这样做的人会看到不正确的行为。你的意思是,当他们读到那个值时,他们可能会得到一个过早的、错误的 EOF,该值在提升到 时恰好相等,而不是永远循环,因为没有人会永远相等。解决方案仍然是一样的:((charVar = getchar()) == EOF)charEOFintcharEOF((intVar = getchar()) == EOF)
1赞 Eric Postpischil 7/20/2019
@Santropedro:是的,答案是错误的。各种标准库例程将字符作为转换为 的字符返回,因此该字符必须具有非负值,该值不能等于,因为是负数。然而,C 标准中“字符”的定义之一是“适合字节的位表示”。许多人使用类型处理字符,该类型可能是带符号的。(实际上,需要一个 .然后,可以有一个 其值相等,但可以有效地打印 和 和其他函数。unsigned charintEOFEOFcharfgetschar *char xEOFfputc
1赞 Eric Postpischil 7/20/2019
@Santropedro:为了正确回答这个问题,这意味着应该使用函数的返回值进行检测,例如 ,该函数返回一个字符作为转换为或 .除了我提供的链接中讨论的奇异假设 C 实现之外,这将适用于所有实现。(若要为这些实现编写代码,请使用该函数。但不应假设一个值不等于 .EOFfgetcunsigned charintEOFfeofcharEOF
3赞 Axel Rietschin 9/2/2014 #7

Windows 上的命令解释器(以及 MSDOS 和 CP/M)识别的字符是 0x1a(十进制 26,又名 + 又名 SUB)EOFCtrlZ

例如,它今天仍然可以用于标记二进制文件中人类可读标头的末尾:如果文件以开头,用户可以使用命令将文件内容转储到控制台,转储将在字符处停止,即打印一些描述并停止,而不是继续后面的垃圾。"Some description\x1a"TYPEEOF

1赞 Harsh Vardhan 3/27/2016 #8

EOF 的价值不能与任何真实角色混淆。

如果 ,那么我们必须声明足够大以容纳任何返回的值。我们不能使用,因为除了字符之外,还必须足够大才能容纳 EOF。a= getchar()agetchar()chara

评论

0赞 Luke Taylor 3/27/2016
这个答案是模棱两可的。虽然第一部分是正确的,但描述大小的第二部分很难理解。我编辑了你的帖子,以便更清晰一点。a
1赞 betontalpfa 2/23/2017 #9

答案是否定的,但是......

您可能会因为以下行为而感到困惑fgets()

http://www.cplusplus.com/reference/cstdio/fgets/

从流中读取字符,并将它们作为 C 字符串存储到 str 中,直到读取 (num-1) 个字符或到达换行符或文件末尾,以先到者为准。

6赞 carloswm85 2/16/2018 #10

我已经阅读了所有评论。有趣的是,当你打印出这个时会发生什么:

printf("\nInteger =    %d\n", EOF);             //OUTPUT = -1
printf("Decimal =    %d\n", EOF);               //OUTPUT = -1
printf("Octal =  %o\n", EOF);                   //OUTPUT = 37777777777
printf("Hexadecimal =  %x\n", EOF);             //OUTPUT = ffffffff
printf("Double and float =  %f\n", EOF);        //OUTPUT = 0.000000
printf("Long double =  %Lf\n", EOF);            //OUTPUT = 0.000000
printf("Character =  %c\n", EOF);               //OUTPUT = nothing

正如我们在这里看到的,EOF不是一个角色(无论什么)。

评论

0赞 phuclv 8/23/2020
你得到UB,因为你使用了错误的格式说明符。 不是浮点数、双精度或长双精度,所以显然将其打印为浮点类型不起作用EOF
0赞 carloswm85 9/29/2020
@phuclv 你能告诉我什么是UB吗?
1赞 phuclv 9/29/2020
未定义的行为 当我使用错误的格式说明符时会发生什么?
1赞 szmoore 8/27/2021
未定义的行为意味着它没有在 C 标准中定义,但并不意味着该行为永远没有原因。当您打印该值时,库函数会从堆栈中读取 8 个字节,其中最后 4 个字节是您可以从中看到的 ,并将这 8 个字节解释为 .它很可能看到一个非常小的非零非规范化值,该值打印为 0.00000000,因为只有 6 个小数位。其他 4 个字节可能在这里,但它们可以是任何东西;因此,“未定义的行为”,您可能会看到其他随机的废话。double0xFFFFFFFF%xdouble0x00
1赞 Samarthya Singh 12/18/2020 #11

我一直在研究很多关于EOF信号的知识。在 Dennis Ritchie 的 C 编程一书中,在介绍 putchar() 和 getchar() 命令时首次遇到它。 它基本上标志着字符串输入的末尾。

例如。让我们编写一个程序来寻找两个数字输入并打印它们的总和。您会注意到,在每次数字输入后,您按 Enter 键以标记已完成 iput 操作的信号。但是,在处理字符串时,Enter 仅被读取为另一个字符 ['\n': 换行符]。要标记输入的终止,请在全新的行中输入 ^Z(在键盘上按 Ctrl + Z),然后输入。这表示要执行的下一行命令。

#include <stdio.h>

int main()
{
char c;
int i = 0;
printf("INPUT:\t");
c = getchar();

while (c != EOF)
{
   ++i;
   c = getchar();
   
};

printf("NUMBER OF CHARACTERS %d.", i);

return 0;}

以上是计算字符数的代码,包括 '\n'(换行符)和 '\t'(空格)字符。如果您不想计算换行符,请执行以下操作:

#include <stdio.h>

int main()
{
char c;
int i = 0;
printf("INPUT:\t");
c = getchar();

while (c != EOF)
{
    if (c != '\n')
    {
        ++i;
    }

    c = getchar();
    };

printf("NUMBER OF CHARACTERS %d.", i);

return 0;}. 

现在主要思考 HOOW 提供输入。这很简单: 写下你想要的所有故事,然后进入一个新行并输入^Z,然后再次输入。