C – stdin缓冲区中已有数据时,在stdin上选择()

select函数阻止调用进程,直到在任何指定的文件描述符集上存在活动[…]如果读取调用不会阻塞,则认为文件描述符已准备好进行读取。 (参见: https : //www.gnu.org/software/libc/manual/html_node/Waiting-for-I_002fO.html )

所以我预计,如果你在第一次迭代中输入一个> 4个字符的字符串,那么在下面的程序中选择将立即返回第二个…迭代。 但事实并非如此。 在第一次输出后按任何其他键之后,它继续处理所有剩余的输入。 为什么?

样本输出:

./selectTest 12345678900 Keyboard input received: 1234 A Keyboard input received: 5678 Keyboard input received: 900 Keyboard input received: A 

 #include  #include  #include  #include  int main(void) { fd_set rfds; char buf[100]; while(1) { FD_ZERO(&rfds); FD_SET(fileno(stdin), &rfds); if(-1 == select(FD_SETSIZE, &rfds, NULL, NULL, NULL)) { perror("select() failed\n"); } if(FD_ISSET(fileno(stdin), &rfds)) { printf("Keyboard input received: "); fgets(buf, 5, stdin); printf("%s\n", buf); } } return 0; } 

(我知道,我不应该再使用select(),但我正在学习考试,我们必须…)

你是从tty(4)读取的(通常情况下stdin是你的终端)。 这些都是棘手的事情,阅读tty揭秘 。

请注意,您的终端及其tty有一些线路规则 。 因此,一些数据在内核中缓存(也在标准库中)。

您可能希望将tty置于原始模式。 见termios(3) & stty(1)

但是不要浪费你的时间,而是使用像ncurses或readline这样的库

要使用select ,你可以使用一些fifo(7) ,也许使用mkfifo /tmp/myfifo然后你的程序yourprogram < /tmp/myfifo ,在另一个终端中,使用echo hello > /tmp/myfifo

从根本上说,问题在于您将缓冲的stdio流与低级I / O混合在一起。 select阻塞的原因是因为先前已输入的数据已经被读取并且被缓存在stdin的流数据缓冲区中。 尝试通过调用setbuf(stdin, NULL)stdin设置为无缓冲模式。