在 C 中导致 gets() 在 SIGINT 上退出

Cause gets() to exit on SIGINT in C

我正在编写一个简单的 C 程序,它使用 gets() 函数一次从键盘(循环)读取一行文本。

如果用户按下 CTRL-C,循环必须立即退出。我知道如何编写一个 sig 处理程序,它可以设置一个标志来退出循环......但是我如何在这个信号到达时立即使 gets() 函数return?

您应该使用 select() 在从标准输入读取之前检查数据是否可用:

void handler (int arg) {
    // handle signal
}

int main (void) {
    char buf[100];
    signal(SIGINT, handler);
    do {
       fd_set f;
       FD_ZERO(&f);
       FD_SET(fileno(stdin), &f);
       int st = select(fileno(stdin)+1, &f, NULL, NULL, NULL);
       if (st == 1) {
          fgets(buf, sizeof(buf), stdin);
          // Handle input
       }
    } while (st >= 0);

    exit(EXIT_SUCCESS);
}

select() 将 return 与 -1 (errno EINTR) 在从信号处理程序 returning 之后,而 read() (由 (f) 调用gets) 将自动恢复。

使用linux,还有另一种可能使用sigaction()

void handler (int arg) {
    // handle signal
}

int main (void) {
    char buf[100], *p;
    struct sigaction sa = { .sa_handler = handler, .sa_flags = 0, .sa_mask = 0 };
    sigaction(SIGINT, &sa, NULL);

    do {    
            p = fgets(buf, sizeof(buf), stdin);
            // handle input
    } while (p);
    printf("Byebye\n");

    exit(EXIT_SUCCESS);
}

由于在 sa_flags 中没有为信号处理程序指定标志 SA_RESTART,因此 slow 设备上的 read()(即终端、管道、插座)也将 return 和 -1 (EINTR)(另请参见 signal(7))。

虽然更简单一些,但不同 unix-flavors(甚至 kernel-versions)之间的行为可能会有所不同,因此第一个版本是更安全且更 portable/reliable 的方式。