如何避免getc导致read函数被阻塞的问题?
问题根源
问题出在标准IO库(stdio)的用户态缓冲机制与系统调用read的直接读取行为冲突:
getc是stdio库函数,它会先把内核缓冲区里的输入数据批量读到stdio自己的用户态缓冲中,再从中取数据返回。read是系统调用,直接读取内核态的标准输入缓冲区,不会理会stdio的用户态缓冲。
当输入"abcdef"时,整个输入会被内核接收,随后stdio库将所有数据读到自己的用户态缓冲里。第一个getc从stdio缓冲取走了'a',此时内核缓冲区已经空了,所以read调用返回0;而第二个getc仍然可以从stdio缓冲里取走'b',就出现了你看到的输出。
解决方案
方案1:统一使用标准IO库函数,避免混合调用
把read替换为stdio库的fread,所有输入操作都走stdio的缓冲机制,就不会出现冲突:
#include <unistd.h> #include <stdio.h> int main() { char buf[6]; printf("%c\n", (char)getc(stdin)); size_t ret = fread(buf, 1, 5, stdin); printf("%zu\n", ret); printf("%c\n", (char)getc(stdin)); }
输入"abcdef"时,fread会从stdio缓冲中读取后续的5个字符("bcdef"),此时getc会因缓冲为空而阻塞等待新输入(如果输入仅为"abcdef"的话)。
方案2:禁用标准IO的缓冲机制
如果必须混合使用getc和read,可以通过setvbuf禁用stdio的输入缓冲,让getc直接调用系统读取内核数据,和read的行为保持一致:
#include <unistd.h> #include <stdio.h> int main() { // 禁用stdin的用户态缓冲,所有IO直接操作内核缓冲区 setvbuf(stdin, NULL, _IONBF, 0); char buf[6]; printf("%c\n", (char)getc(stdin)); int ret = read(STDIN_FILENO, buf, 5); printf("%d\n", ret); printf("%c\n", (char)getc(stdin)); }
此时输入"abcdef",getc读取'a'后,read会直接从内核读取后续的5个字符("bcdef")并返回5,最后一个getc会因内核缓冲区为空而阻塞。
方案3:手动同步缓冲(不推荐)
可以使用fflush(stdin)强制刷新stdio缓冲,但注意**fflush(stdin)属于非标准行为**,仅部分编译器(如GCC)支持,移植性差,不建议在生产代码中使用。
内容的提问来源于stack exchange,提问作者Wei Li
相关产品推荐
相关产品推荐

