Ctrl-C 被 getchar() 吃掉
我长期以来一直在寻找问题的解决方案,这就是我向您求助的原因:
考虑这段代码:
static char done = 0;
static void sigHandler(void)
{
done = 1;
}
int user_input()
{
return (getchar() == 'q') ? 0 : 1;
}
int main(void)
{
signal(SIGTERM, sigHandler);
signal(SIGINT, sigHandler);
while (user_input() != 0 && !done)
usleep(1000);
printf("exiting\n");
return 0;
}
预期的行为: 当用户输入 q 然后输入时程序退出。如果按下CTRL+C,则会被 sigHandler 函数捕获,该函数将标志“done”设置为 1 并退出程序。
观察到的行为: CTRL+C 字符被 getchar() 调用吃掉,并且 sigHandler 函数永远不会执行。当按下 CTRL+C 并按下 Enter 时,将调用 sigHandler 函数并退出程序。
有更多经验和知识的人可以帮助我解决这一问题吗?
感谢您的投入:)
I've been searching for a solution to my problem for a long time now that's why i'm turning to you:
Consider this piece of code:
static char done = 0;
static void sigHandler(void)
{
done = 1;
}
int user_input()
{
return (getchar() == 'q') ? 0 : 1;
}
int main(void)
{
signal(SIGTERM, sigHandler);
signal(SIGINT, sigHandler);
while (user_input() != 0 && !done)
usleep(1000);
printf("exiting\n");
return 0;
}
Expected behavior:
The program exits when user inputs q then enter. If CTRL+C is pressed, it is caught by the sigHandler function which sets the flag 'done' to 1 and exits the program.
Observed behavior:
The CTRL+C character is eaten by the getchar() call, and the sigHandler function is never executed. When CTRL+C and then enter is pressed, the sigHandler function is called and the program exits.
Could someone with more experience and knowledge help me on that one?
Thanks for your input :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
Ctrl-C 不会被
getchar
吃掉;它会导致信号被传递并且 sigHandler 被运行。这会设置done
并返回。 只有这样才会调用getchar
,它会吃掉换行符,之后会检查done
,以便程序退出。顺便说一句,信号处理程序采用
int
参数,而不是void
。Ctrl-C is not eaten by
getchar
; it results in a signal being delivered andsigHandler
being run. This setsdone
and returns. Only then isgetchar
called, which eats the newline and after that,done
is checked so the program exits.Btw., a signal handler takes an
int
argument, notvoid
.有一种方法可以中止呼叫,而无需诉诸丑陋的黑客手段(与 Paul R 所说的相反)。您应该使用将
sa_flags
设置为0
的sigaction()
,而不是signal()
。此外,signal(2)手册说:
通常,在捕获并处理信号后,大多数(我不确定是否不是全部)系统调用将重新启动。这样,在处理 sigint 信号后,您的 getchar 函数将继续执行,就像什么也没发生一样。
您可以通过使用
sa_flags=0
调用 sigaction 来更改此行为。这样,在处理 SIGINT 后,
getchar
将返回-1
并且 errno 将被设置为“Interrupted system call”(我现在不记得常量名称了)。您还必须重写 user_input() 函数来处理返回 -1 时的情况。
There IS a way to abort the call without resorting to ugly hacks (contrarily to what Paul R said). You should use
sigaction()
withsa_flags
set to0
instead ofsignal()
.Besides, the signal(2) manual says:
Normally, after catching and handling a signal, most (I'm not sure if not all) syscalls will be restarted. This way, after handling the sigint signal, your getchar function will continue as if nothing happened.
You can change this behavior by calling sigaction with
sa_flags=0
.This way, after handling SIGINT,
getchar
will return-1
and errno will be set to "Interrupted system call" (I don't remember the constant name right now).You would also have to rewrite your user_input() function to handle the case when returning -1.
代码实际上按预期工作 - 在从
user_input()
返回之前,您不会测试done
标志,这就是为什么您需要在控制-C。如果您想在获得 control-C 时中止对
getchar
的调用,那么您可能必须做一些难看的事情,例如使用setjmp
/longjmp< /代码>。
The code is actually working as expected - you are not testing the
done
flag until after you return fromuser_input()
, which is why you need to enter an additional character after the control-C.If you want to abort the call to
getchar
when you get a control-C then you'll probably have to do something ugly, e.g. usesetjmp
/longjmp
.