为什么C程序在使用Ctrl+D发送EOF时会打印0D而不是0?

14

OSX 10.6.8, GCC 4.2 86_64

#include <stdio.h>

/* count lines in input */
main()
{
    int c, nl;

    nl = 0;
    while ((c = getchar()) != EOF)
        if (c == '\n')
            ++nl;
    printf("%d\n", nl);
}

运行

./a.out

按下Ctrl+D发送EOF信号。

0D

应该只是0。为什么会附加D?它是什么意思?


5
如果你按下ctrl+D,那么听起来D是来自终端...例如,它与printf(或代码)没有关系吗?如果你尝试使用moreless进行操作会发生什么?如果将输入管道传递到程序中会怎样? - user166390
2
每次您使用<kbd>CTR</kbd> <kbd>D</kbd>发送EOF时,是发生在任何程序中还是只发生在这个测试程序中?我认为0旁边的D只是来自上面的键组合。 - Nicolás Ozimica
当我在我的Linux机器上运行时,得到了0。 - Jeegar Patel
@Nicolás 不,只有这个例子。 - Dmitry
2
请参阅:添加D到输出的简单程序 - Jonathan Leffler
显示剩余2条评论
1个回答

21
我看过这个问题,它也让我感到困惑。
终端会回显字符"^D",然后程序输出"0",覆盖了插入符号。
你可以通过将程序的打印格式更改为"\n%d\n"来演示这一点。
当被问及“为什么?”时,我进行了探索。答案在tty设置中。对于我的终端,stty -a 的输出如下:
speed 9600 baud; 65 rows; 120 columns;
lflags: icanon isig iexten echo echoe -echok echoke -echonl echoctl
    -echoprt -altwerase -noflsh -tostop -flusho pendin -nokerninfo
    -extproc
iflags: -istrip icrnl -inlcr -igncr ixon -ixoff ixany imaxbel iutf8
    -ignbrk brkint -inpck -ignpar -parmrk
oflags: opost onlcr -oxtabs -onocr -onlret
cflags: cread cs8 -parenb -parodd hupcl -clocal -cstopb -crtscts -dsrflow
    -dtrflow -mdmbuf
cchars: discard = ^O; dsusp = ^Y; eof = ^D; eol = <undef>;
    eol2 = <undef>; erase = ^?; intr = ^C; kill = ^X; lnext = ^V;
    min = 1; quit = ^\; reprint = ^R; start = ^Q; status = ^T;
    stop = ^S; susp = ^Z; time = 0; werase = ^W;

注意第二行末尾的echoctl - 它是用于“回显控制字符”的。

$ stty -echoctl
$ cat > /dev/null
asdsadasd
$ stty echoctl
$ cat > /dev/null
asasada^D
$

你看不到它,但对于每个cat命令,我在asd字符的行末打了一个Control-D,以及在按回车后的第二次。在第二个示例中,提示符删除了第二个回显的^D

因此,如果您不喜欢控制字符被回显,请将其关闭:

stty -echoctl

Shell也可能会阻碍操作。我尝试使用 Control-R,结果我的shell (bash)陷入了困境。

(reverse-i-search)`': aasadasdadadasdadadadadadsad

我输入了不太原创的字符序列'asd',然后按下了Control-R键,在shell中就会出现以下内容。我打断了这个过程;我不确定反向搜索是什么,但我怀疑它与Emacs有关;这不是我预期的结果。


哇,那真是太准确了!但为什么它只在这种特殊情况下发生?或者它是否一直发生?为什么会回显 ^D? - Dmitry
1
非常感谢您进行所有这些研究!看到实现方式非常有趣。 - Dmitry

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接