C语言中getline()遇SIGINT后不等待输入的原因问询
关于SIGINT中断后getline行为的疑问
我写了一段极简代码,用来读取用户输入并处理SIGINT(Ctrl+C)信号,用sigaction实现。本来预期按下Ctrl+C后换行并显示$等待输入,代码居然意外达成了预期效果,但我有个疑问:操作系统处理完中断后,getline为何不恢复等待输入,而是直接继续执行?
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <string.h> volatile sig_atomic_t sigint_received = 0; static void handler(int signum) { sigint_received = 1; } int main() { struct sigaction sa; sa.sa_handler = handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGINT, &sa, NULL); char *line = NULL; size_t n = 100; line = malloc(n); while(1){ if(sigint_received){ sigint_received = 0; printf("\n"); } printf("$ "); getline(&line, &n, stdin); if(!strcmp(line, "exit\n")){ break; } } if(line){ free(line); } return 0; }
这是因为当进程在调用getline这类阻塞式系统调用时收到信号,系统调用会被中断并返回错误(错误码为EINTR),而非继续阻塞等待输入。
你的代码没有检查getline的返回值,所以当SIGINT触发后,getline被中断直接返回-1,代码会跳过后续的判断逻辑,回到循环开头:检查sigint_received标志、换行、重新打印$,然后再次调用getline等待输入,刚好达成了你想要的效果。
如果要让代码更严谨,建议添加getline的返回值检查:
ssize_t ret = getline(&line, &n, stdin); if (ret == -1) { // 若为信号中断导致的错误,直接继续循环即可 if (errno == EINTR) { continue; } // 处理其他类型的错误 perror("getline failed"); break; }
另外,你用volatile sig_atomic_t来存储信号标志的做法是正确的,这是信号处理函数中修改全局变量的标准方式,能避免编译器优化带来的问题。
内容的提问来源于stack exchange,提问作者haccks
相关产品推荐
相关产品推荐

