导致get()在C中的SIGINT上退出

时间:2016-01-25 14:39:31

标签: c gets sigint

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

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

1 个答案:

答案 0 :(得分:1)

在从stdin读取之前,您应该使用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()将返回-1(错误EINTR),而read()(由(f)获取)将自动恢复。

使用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_RESTART中未指定标记sa_flags,因此设备上的read()(即终端,管道,套接字) )也会以-1 (EINTR)返回(另见信号(7))。

虽然稍微简单一些,但不同的unix-flavors(甚至内核版本)之间的行为可能会有所不同,因此第一个版本是更安全,更便携/可靠的方式。