简体   繁体   English

Ctrl-C被getchar()吃掉

[英]Ctrl-C eaten by getchar()

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. 预期行为:当用户输入q然后输入时,程序退出。 If CTRL + C is pressed, it is caught by the sigHandler function which sets the flag 'done' to 1 and exits the program. 如果按下CTRL + C ,它将被sigHandler函数捕获,该函数将标志'done'设置为1并退出程序。

Observed behavior: The CTRL + C character is eaten by the getchar() call, and the sigHandler function is never executed. 观察到的行为: CTRL + C字符被getchar()调用吃掉,并且从不执​​行sigHandler函数。 When CTRL + C and then enter is pressed, the sigHandler function is called and the program exits. 按下CTRL + C然后按Enter键时,将调用sigHandler函数并退出程序。

Could someone with more experience and knowledge help me on that one? 有经验和知识的人可以帮助我吗?

Thanks for your input :) 感谢您的输入 :)

The code is actually working as expected - you are not testing the done flag until after you return from user_input() , which is why you need to enter an additional character after the control-C. 代码实际上正在按预期工作 - 直到从user_input()返回之后才测试done标志,这就是为什么你需要在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, eg use setjmp / longjmp . 如果你想在获得control-C时中止对getchar的调用,那么你可能不得不做一些丑陋的事情,例如使用setjmp / longjmp

The Ctrl-C character is eaten by the getchar() call, and the sigHandler function is never executed. Ctrl-C字符被getchar()调用吃掉,并且从不执​​行sigHandler函数。

Ctrl-C is not eaten by getchar ; getchar不会吃掉Ctrl-C; it results in a signal being delivered and sigHandler being run. 它导致传递信号并运行sigHandler This sets done and returns. 这设置done并返回。 Only then is getchar called, which eats the newline and after that , done is checked so the program exits. 只有这样才会调用getchar ,它会占用换行符, 然后检查done ,以便程序退出。

Btw., a signal handler takes an int argument, not void . 顺便说一下,信号处理程序接受一个int参数,而不是void

There IS a way to abort the call without resorting to ugly hacks (contrarily to what Paul R said). 有一种方法可以在不诉诸丑陋的黑客的情况下中止呼叫(与Paul R所说的相反)。 You should use sigaction() with sa_flags set to 0 instead of signal() . 你应该使用sa_flags设置为0而不是signal() sigaction() signal()

Besides, the signal(2) manual says: 此外,信号(2)手册说:

Avoid its use : use sigaction (2) instead. 避免使用 :改为使用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;
}

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. 这样,在处理了sigint信号之后,你的getchar函数将继续,好像什么都没发生一样。 You can change this behavior by calling sigaction with sa_flags=0 . 您可以通过使用sa_flags=0调用sigaction来更改此行为。

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

You would also have to rewrite your user_input() function to handle the case when returning -1. 您还必须重写user_input()函数来处理返回-1时的情况。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM