Ctrl 信号用 EOF 填充标准输入?
Ctrl signals fills stdin with EOF?
我正在做一个解析器获取 EOF
之前的字符,我正在处理信号 SIGTERM
、SIGINT
、SIGTSTP
和 SIGQUIT
。因此,当我使用 Ctrl+C 发送信号时( 例如 SIGINT
)信号处理程序打印 Ctrl+C 然后必须继续,但不会继续。
我发现在每个 Ctrl 信号之后,一个 EOF
正在填充缓冲区,但我不知道如何摆脱它。我试图在处理程序中执行 while(getc(stdin) != EOF);
,但解析器运行正常,"eating" 每个字符键入直到 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 - %c\n", 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
调用将 return 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 不是其中之一),您可能想要取消注释它,特别是因为它不应该以其他方式损害流程代码。
我实际上认为该行为可能违反了标准,因为它明确指出:
If the end-of-file indicator for the stream is set, or if the stream is at end-of-file, the endoffile indicator for the stream is set and the fgetc function returns EOF. Otherwise, the fgetc function returns the next character from the input stream pointed to by stream. If a read error occurs, the error indicator for the stream is set and the fgetc function returns EOF.
换句话说,没有提到前面的错误指示器阻止了未来的读取。我能看到被允许的唯一方法是文本 "a read error occurs" 是否包含事件 "a read error has previously occurred and the error indicator has not been reset",这对我来说似乎有点牵强。
如果您不想在处理信号后处理读取调用的错误,您可以在信号处理程序上设置 SA_RESTART
标志:
s.sa_flags = SA_RESTART;
这将导致 getc
调用不会因信号处理程序的 EINTR
错误而中断。
我正在做一个解析器获取 EOF
之前的字符,我正在处理信号 SIGTERM
、SIGINT
、SIGTSTP
和 SIGQUIT
。因此,当我使用 Ctrl+C 发送信号时( 例如 SIGINT
)信号处理程序打印 Ctrl+C 然后必须继续,但不会继续。
我发现在每个 Ctrl 信号之后,一个 EOF
正在填充缓冲区,但我不知道如何摆脱它。我试图在处理程序中执行 while(getc(stdin) != EOF);
,但解析器运行正常,"eating" 每个字符键入直到 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 - %c\n", 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
调用将 return 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 不是其中之一),您可能想要取消注释它,特别是因为它不应该以其他方式损害流程代码。
我实际上认为该行为可能违反了标准,因为它明确指出:
If the end-of-file indicator for the stream is set, or if the stream is at end-of-file, the endoffile indicator for the stream is set and the fgetc function returns EOF. Otherwise, the fgetc function returns the next character from the input stream pointed to by stream. If a read error occurs, the error indicator for the stream is set and the fgetc function returns EOF.
换句话说,没有提到前面的错误指示器阻止了未来的读取。我能看到被允许的唯一方法是文本 "a read error occurs" 是否包含事件 "a read error has previously occurred and the error indicator has not been reset",这对我来说似乎有点牵强。
如果您不想在处理信号后处理读取调用的错误,您可以在信号处理程序上设置 SA_RESTART
标志:
s.sa_flags = SA_RESTART;
这将导致 getc
调用不会因信号处理程序的 EINTR
错误而中断。