Ctrl-C被getchar()吃掉

时间:2011-11-02 09:45:26

标签: c unix signals 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并退出程序。

观察到的行为: getchar()调用会使用 CTRL + C 字符,并且永远不会执行sigHandler函数。当 CTRL + C 然后按下Enter时,将调用sigHandler函数并退出程序。

有经验和知识的人可以帮助我吗?

感谢您的意见:)

3 个答案:

答案 0 :(得分:5)

代码实际上按预期工作 - 在从done返回之前,您没有测试user_input()标志,这就是为什么您需要在control-C之后输入一个额外的字符。< / p>

如果你想在获得一个控制C时中止对getchar的调用,那么你可能不得不做一些丑陋的事情,例如:使用setjmp / longjmp

答案 1 :(得分:5)

  

getchar()调用会吃掉Ctrl-C字符,并且永远不会执行sigHandler函数。

getchar不会吃掉Ctrl-C;它会导致传递信号并运行sigHandler。这会设置done并返回。 只有 getchar被调用,它会占用换行符,之后done被检查以便程序退出。

顺便说一句,信号处理程序采用int参数,而不是void

答案 2 :(得分:4)

有一种方法可以在不诉诸丑陋的黑客的情况下中止呼叫(与Paul R所说的相反)。您应该sigaction()使用sa_flags设置为0而不是signal()

此外,信号(2)手册说:

  

避免使用:改为使用 sigaction (2)。

#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <errno.h>

static char done = 0;
static void sigHandler(int signum)
{
    done = 1;
}

int user_input()
{
    return (getchar() == 'q') ? 0 : 1;
}

int main(void)
{
    struct sigaction sa;
    memset(&sa, 0, sizeof(struct sigaction));
    sa.sa_handler = sigHandler;
    sa.sa_flags = 0;// not SA_RESTART!;

    sigaction(SIGINT, &sa, NULL);
    sigaction(SIGTERM, &sa, NULL);

    while (user_input() != 0 && !done)
        usleep(1000);
    printf("exiting\n");
    return 0;
}

通常,在捕获和处理信号后,大多数(我不确定是否全部)系统调用将重新启动。这样,在处理了sigint信号之后,你的getchar函数将继续,好像什么都没发生一样。 您可以通过使用sa_flags=0调用sigaction来更改此行为。

这样,在处理SIGINT之后,getchar将返回-1并且errno将被设置为“Interrupted system call”(我现在不记得常量名称)。

当你返回-1时,你还必须重写你的user_input()函数来处理这个案例。