为什么我需要多个EOF(CTRL + Z)字符?

时间:2011-04-13 20:20:38

标签: c windows-xp cmd eof

作为一个小背景,我对C编程语言很陌生,因此一直试图通过第二版Kernighan& amp; Ritchie手册。我确实意识到我可以通过更多地使用标准库来更简洁地处理某些问题,但我正在尝试尽可能地使我的有用命令保持与书本同步。

如果它有所不同,我正在使用Tiny C编译器(TCC)在Windows XP环境中编译源代码,并在XP控制台(cmd.exe)中执行二进制文件。

问题:处理End-of-File (EOF) characters。我已经整理了一个小测试用例来说明问题。该程序似乎处理EOF字符(部分)。我将尝试用样本输入/输出来演示这个问题。

#include <stdio.h>

int main() 
{
    int character, count;

    character = 0;
    character = getchar();

    for (count = 0; character != EOF; ++count) 
    {
        character = getchar();
    }

    printf("Count: %d", count);
    return 0;
}

示例输入1:abcd^Z[enter](其中^ Z / CTRL + Z表示EOF字符,[enter]表示Enter键。)

示例输出1:Count: 4(等待更多输入或在^ C / ^ Z [enter]上正确结束)

示例输入2:abcd^Zefgh

示例输出2:Count: 4(等待更多输入或在^ C / ^ Z [enter]上正确结束)

如两个示例中所述,在启动^ C / ^ Z [enter]序列之前不输出字符计数。在启动之前,程序会等待(并确实处理)更多输入。但是,如示例2中所述,当程序遇到初始^ Z时,它会停止处理该输入行,等待更多输入或在启动^ C / ^ Z [enter]序列时返回正确的计数。

我无法弄清楚为什么程序只是部分处理EOF字符。在我看来,如果它截断样本2的末尾,它也应该完全脱离循环。任何想法为什么在识别EOF字符时程序不会立即打印当前计数并退出?

5 个答案:

答案 0 :(得分:7)

这个答案是unix-ish,但我认为在Windows上发生了类似的现象。 EOF的基本形式是零长度read。在交互式输入设备(终端)上,有一种在输入流中具有EOF的特殊机制,但是如果已经有要读取的输入,则它将与该输入一起被消耗(导致非零长度{{1} })因此从未被应用程序注意到。只有在没有事先输入缓冲的情况下发生EOF时,才能注意到应用程序并对其采取行动。

如果您可以访问Linux(或其他* nix)系统,请编写类似的测试程序并在read下运行它。观察发生的基础strace调用,这种不合情理的行为的原因是有道理的。

答案 1 :(得分:2)

这可以追溯到计算的石器时代。至少CP / M,可能早于DEC操作系统。 CP / M没有存储文件的大小,它只跟踪磁盘扇区的数量,每个128字节。二进制文件不是问题,程序只有在足够的时候停止读取。但肯定是文本文件的问题。

因此按照惯例,文本文件的结尾标有代码0x1a,Control + Z.背负着大于其中文本数量的文本文件的遗留问题,这必须在每一代CRT实现中继续进行。 Windows没有对此发表评论,这纯粹是一个CRT实现细节。这就是为什么在控制台上键入Ctrl + Z并没有做任何特别的事情。按Enter键后,cmd.exe中的CRT将再次调用旧行为并声明EOF。

答案 2 :(得分:0)

我不确定TCC,但在很多(大多数?)情况下,你需要或多或少地输入^ Z,因为它被识别为EOF(即,你需要一个序列[enter] ^ z [enter])。

答案 3 :(得分:0)

键入^ Z时,Windows不会自动生成EOF;这只是DOS上的一项约定。 C编译器的运行时必须识别它并设置EOF标志,我猜Tiny C不会这样做。

另一方面,

^ C 被Windows命令环境识别。它并不一定意味着EOF,我认为它更像是一个中止信号。

答案 4 :(得分:0)

我猜标准输入是行缓冲的(它在Unix上)。 DOS有一些低于stdio的getch()getche()函数,因此它们绕过了stdio缓冲。我不知道如何在Windows上禁用输入缓冲,在Unix上通过将终端设置为非规范模式来完成。