c - 在循环中使用 scanf 处理 SIGINT

标签 c signals scanf sigint

我必须在 while 循环中获取用户的输入,然后采取一些操作。我还想通过 ctrl+c 输入退出我的代码。

void my_signal_handler(int sig)
{
    running = false;
    signal(sig, SIG_IGN);
}
int main(void)
{
    struct sigaction sa = {{0}};
    sa.sa_handler = &my_signal_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;

    if (sigaction(SIGINT, &sa, NULL) != 0)
    {
        fprintf(stderr, "sigaction error\n");
        return -1;
    }
    while(running)
    {
        printf("enter number: ");
        scanf("%d", &num);
        // take action based on  number
    }
}

此代码的问题是按 ctrl+c 后,它不会退出,但会等待 scanf 的输入。因此,一旦我按下额外的键,程序就会退出(信号处理程序被调用)。

如何删除按 ctrl+c 后向 scanf 提供输入的这个额外步骤?

最佳答案

您应该安装信号处理程序。至少,添加

signal(SIGINT, my_signal_handler);

在你的main之前while(running),但最好使用sigaction(2) .

您还应该知道 stdiobuffering ;通常,当 stdout 是终端时,它是行缓冲的(但请参阅 setvbuf(3) 和 friend )。所以你应该调用 fflush(3) (可能如 fflush(NULL);)在循环内的 scanf 之前,或使用显式终止每个 printf 格式控制字符串 \n.

最后,scanf(3)可能会失败并返回已扫描项目的数量,您应该对此进行测试。

顺便说一句,您的 main 是错误的,应定义为 int main(void) 或最好 int main(int argc, char**argv).

但是(假设您使用的是 Linux),请仔细阅读 signal(7) (注意关于信号处理程序和异步信号安全函数的说法)和 POSIX signal.h documentation并将您的 running 标志声明为

volatile sigatomic_t running;

(或者,在 C11 中,作为 volatile _Atomic bool running;)

volatile qualifier非常重要。否则,允许编译器进行优化(例如,假设running始终为真)。

请注意,使用 signal(2)通常是一个坏主意。首先,如果你确实需要信号处理,你最好使用 sigaction(2) 。那么您对 ​​signal(sig, SIG_IGN); 的调用在您的情况下是无用的(因为 running volatile 标志将在信号处理程序中更改)。最后,对于多路复用输入(和输出),您可以使用 poll(2)它可用于等待并测试 stdin 上是否有可用输入(实际上 STDIN_FILENO 为 0),更一般地用于实现 event loops 。您可以使用(而不是我强烈推荐的 poll)旧的且几乎过时的 select(2) ,但您更愿意使用 poll(2) 。另请参阅epoll(7) & inotify(7)但您可能不需要它们。

请注意,在终端中,stdin 通常是一个 tty(使用 isatty(3) 检查),后面是 line discipline。 (因此一些行缓冲发生在内核内部)。阅读tty demystified页。考虑使用GNU readline库和函数(或者可能 ncurses ),这可能是您真正需要的。

另请阅读Advanced Linux Programming并养成阅读您正在使用的每个函数的文档的习惯。

关于c - 在循环中使用 scanf 处理 SIGINT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38069818/

相关文章:

c# - 使用 C# 作为 C 样式导出库

每 60 毫秒在 c 中创建一个文件来保存位图图像

linux - 传送未阻塞信号需要多长时间?

c - c - 如何将数据从一个进程传递到另一个进程?

c - 从字符串中提取不确定数量的整数

c - 我的快速排序无法正常工作。我做错了什么?

我可以禁用或忽略 Apple 添加到 C 标准头文件吗?

c++ - Visual C++ 2015 中的 SIGINT 处理程序重置

c - 为什么 getchar() 不停止读取 C 中的字符串?

c - c中scanf 3次不起作用?