Ctrl-C 被 getchar() 吃掉

发布于 2024-12-13 09:09:34 字数 719 浏览 0 评论 0原文

我长期以来一直在寻找问题的解决方案,这就是我向您求助的原因:

考虑这段代码:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

静待花开 2024-12-20 09:09:35

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

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

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

The Ctrl-C character is eaten by the getchar() call, and the sigHandler function is never executed.

Ctrl-C is not eaten by getchar; it results in a signal being delivered and sigHandler being run. This sets done and returns. Only then is getchar called, which eats the newline and after that, done is checked so the program exits.

Btw., a signal handler takes an int argument, not void.

没︽人懂的悲伤 2024-12-20 09:09:34

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

此外,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”(我现在不记得常量名称了)。

您还必须重写 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() with sa_flags set to 0 instead of signal().

Besides, the signal(2) manual says:

Avoid its use: use sigaction(2) instead.

#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.
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.

拒绝两难 2024-12-20 09:09:34

代码实际上按预期工作 - 在从 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 from user_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. use setjmp/longjmp.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文