我正在做一个解析器,获取字符直到EOF
,我正在处理信号SIGTERM
、SIGINT
、SIGTSTP
和SIGQUIT
。因此,当我用Ctrl+C(例如发送给SIGINT
)发送信号时,信号处理程序会打印
我发现,在每个Ctrl信号之后,一个EOF
正在填充缓冲区,但我不知道如何消除它。我试图在处理程序中执行while(getc(stdin) != EOF);
,但解析器表现正常,"吃掉"所有键入的字符,直到EOF
。
如何在不干扰stdin
的情况下接收Ctrl信号?
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
static void nsh_signal_handler(int code)
{
char c;
switch(code)
{
case SIGQUIT: c = '\'; break;
}
fprintf(stdout, "I will do nothing about your Ctrl - %cn", c);
}
int main(void)
{
int c;
struct sigaction s;
s.sa_flags = 0;
s.sa_handler = nsh_signal_handler;
sigfillset(&s.sa_mask);
sigaction(SIGQUIT, &s, NULL);
do
{
c = getc(stdin);
printf("[%c][%d]n", c, c);
}
while(c != EOF);
return 0;
}
上面的代码显示了此错误。
getc
调用将为文件的真实结尾或错误条件返回EOF
如果需要区分两者,可以使用feof
或ferror
对于您的特定情况,您可以简单地替换:
while(c != EOF);
带有:
while ((c != EOF) || (! feof(stdin)));
如果角色被信号捕获,那么最好避免尝试输出角色。您可以通过将循环更改为以下内容来实现这一点:
do {
c = getc(stdin);
while ((c == EOF) && (!feof(stdin))) { // throw away CTRL-whatever.
//clearerr (stdin);
c = getc(stdin);
}
printf("[%c][%d]n", c, c); // print true characters and last EOF.
}
while (c != EOF);
您会注意到,在上面的代码中,有一个对clearerr
的调用被注释掉了。如果您的实现是在清除错误标志之前一直提供错误指示的实现之一(Linux不是其中之一),那么您可能需要取消注释它,特别是因为它不应该损害代码流。
事实上,我认为这种行为可能违反了标准,因为它特别指出:
如果设置了流的文件结尾指示符,或者如果流位于文件结尾,则设置了该流的endofile指示符,fgetc函数返回EOF否则,fgetc函数将返回流指向的输入流中的下一个字符如果发生读取错误,将设置流的错误指示器,fgetc函数将返回EOF。
换句话说,没有提及防止未来读取的先前错误指示器。我唯一能看到允许的方式是,如果文本"发生读取错误"包括事件"以前发生过读取错误,错误指示器没有重置",这对我来说似乎有点牵强。
如果您不想在处理信号后处理读取调用中的错误,可以在信号处理程序上设置SA_RESTART
标志:
s.sa_flags = SA_RESTART;
这将导致CCD_ 17调用不会被信号处理器的CCD_。