当通过管道提供STDIN时,getchar()在EOF上循环

pix*_*xis 4 c stdin loops pipe getchar

我面对的是一些我无法解释的事情.除了举例外,没有更好的解释方式:

#include <stdio.h>

int main ()
{
    char c;
    while (1) {
        c = getchar();
        printf("%x\n", c);
    }
   return(0);
}
Run Code Online (Sandbox Code Playgroud)

如果我执行此命令,它只是以这种方式无限迭代:

$ echo -n "A" | ./binary
41
ffffffff
ffffffff
ffffffff
ffffffff
...
Run Code Online (Sandbox Code Playgroud)

从我所知道的和我读(混乱有关的getchar()循环内部是如何工作),我以为echo -n "A"会发A标准输入,然后触发EOF 事件(我不知道什么EOF真的是)一次,因此我的循环最多迭代两次,然后等待stdin中的新输入.

但不,它迭代EOF,我不明白为什么.

我运行此命令试图理解:

$ echo -n "A" | strace ./binary
read(0, "A", 4096)                      = 1
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 4), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ffff7ff6000
write(1, "41\n", 341
)                     = 3
read(0, "", 4096)                       = 0
write(1, "ffffffff\n", 9ffffffff
)               = 9
read(0, "", 4096)                       = 0
write(1, "ffffffff\n", 9ffffffff
)               = 9
...
Run Code Online (Sandbox Code Playgroud)

所以看起来read()没有读任何东西,并返回0,由getchar()解释为EOF.但是为什么,为什么它会像这样迭代,而当我以正常方式执行这个二进制时,它按预期工作:

$ ./binary
A
41
a
B
42
a
^C
$
Run Code Online (Sandbox Code Playgroud)

(上面的输出可能会有点混乱,但是当我进入A然后Return,我送A那么\n(0X0A)到标准输入,所以二进制只是在他们的六交涉显示这些,41a)

有人可以向我解释一下吗?我错过了什么 ?

非常感谢阅读!

Kla*_*äck 5

一旦遇到EOF,getchar将立即返回返回值EOF.流的流指针不会前进,它将保留在EOF标记上.随后的调用getchar也将立即返回,因为流仍在EOF标记处.

请注意,这与stdin附加到输入设备时的行为不同.在这种情况下,getchar如果输入缓冲区为空,将暂停,等待进一步输入.直到从输入设备发送(从Linux中的键盘发送)getchar才会返回.EOFEOFCTRL-DEOF

  • 如果`char`是无符号的,`char c`永远不会比较等于`EOF`.如果`char`为某些非ASCII字符(那些将产生相应的负值作为'EOF`)签名,它将等于`EOF`. (2认同)

Rob*_*obs 5

getchar()返回一个int,而不是一个char.较大的返回值允许您查找返回值EOF,即-1.这是错误和文件结束的返回值.将c的类型更改为int不会更改printf的行为.

#include <stdio.h>

int main ()
{
    int c;
    while (1) {
        c = getchar();
        if ( c == EOF) {
            break;
        }
        printf("%x\n", c);
    }
   return(0);
}
Run Code Online (Sandbox Code Playgroud)