Joh*_*inz 10 c linux stdin polling
我正在编写一个函数,如果stdin中已存在一个字符,则从stdin中读取单个字符.如果stdin为空,则该函数假设不执行任何操作并返回-1.我用Google搜索非阻塞输入并指向poll()或select().首先我尝试使用select(),但我无法让它工作,所以我尝试了poll()并得出了相同的结论.我不确定这些函数究竟是做什么的,但是根据我对poll()的文档的理解,如果我这样调用它:
struct pollfd pollfds;
pollfds = STDIN_FILENO;
pollfds.events = POLLIN;
poll(pollfds, 1, 0);
Run Code Online (Sandbox Code Playgroud)
if(pollfds.revents&POLLIN)如果"可以在不阻塞的情况下读取高优先级数据以外的数据",则为真.但是poll()总是在我的测试情况下超时.我如何测试函数可能是问题,但我想要的功能正是我正在测试的.这是当前的功能和测试情况.
#include <poll.h>
#include <stdio.h>
#include <unistd.h>
int ngetc(char *c)
{
struct pollfd pollfds;
pollfds.fd = STDIN_FILENO;
pollfds.events = POLLIN;
poll(&pollfds, 1, 0);
if(pollfds.revents & POLLIN)
{
//Bonus points to the persons that can tell me if
//read() will change the value of '*c' if an error
//occurs during the read
read(STDIN_FILENO, c, 1);
return 0;
}
else return -1;
}
//Test Situation:
//Try to read a character left in stdin by an fgets() call
int main()
{
int ret = 0;
char c = 0;
char str[256];
//Make sure to enter more than 2 characters so that the excess
//is left in stdin by fgets()
fgets(str, 2, stdin);
ret = ngetc(&c);
printf("ret = %i\nc = %c\n", ret, c);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
您正在做错误的IO,POSIX手册和所有其他相关文档明确表示永远不要混淆在FILE *s和文件描述符上完成的IO .你非常公然违反了这条规则.此规则已到位,因为FILE *s使用缓冲这意味着在调用之后fgets将没有任何东西read可以获取,因为fgets已经将所有待处理数据读入保留在FILE *结构中的缓冲区中.
因此,由于无法检查ISO C IO方法是否会阻塞,我们只能使用文件描述符.
因为我们知道这STDIN_FILENO只是数字0,所以我们可以使用
fcntl (0, F_SETFL, O_NONBLOCK);
Run Code Online (Sandbox Code Playgroud)
这将把read文件描述符0上的所有内容转换为非阻塞模式,如果你想使用不同的文件描述符,那么你可以单独留0,然后只是dup用来复制它.
这样一来,就可以从远离poll完全和实施ngetc为
ssize_t
ngetc (char *c)
{
return read (0, c, 1);
}
Run Code Online (Sandbox Code Playgroud)
或者更好,一个宏
#define ngetc(c) (read (0, (c), 1))
Run Code Online (Sandbox Code Playgroud)
因此,您可以获得所需内容的简单实现.
编辑:如果您仍然担心终端缓冲输入,您可以随时更改终端的设置,请参阅如何禁用程序中xterm的输入行缓冲?有关如何执行此操作的更多信息.
编辑:一个人不能使用fgetc而不是read因为使用fgets不起作用的原因.当其中一个FILE *IO函数运行时,它会从关联的文件描述符中读取所有数据.但是一旦发生这种情况,poll将永远不会返回,因为它正在等待一个总是空的文件描述符,并且会发生同样的事情read.因此,我建议你按照文档的建议,从未混合流(IO使用fgets,fgetc等)和文件描述符(使用IO read,write等等)