我必须在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提供输入的额外步骤?
答案 0 :(得分:1)
您应该安装信号处理程序。至少,添加
signal(SIGINT, my_signal_handler);
1>}之前<{1>} 内的,但最好使用sigaction(2)。
您还应该知道 stdio 是buffering;通常main
在终端时是行缓冲的(但请参阅setvbuf(3)和朋友)。因此,您应该在循环内的while(running)
之前调用fflush(3)(可能为stdout
),或者使用显式fflush(NULL);格式控制字符串> scanf
。
最后,scanf(3)可能会失败,并且会返回您应该测试的已扫描项目的数量。
顺便说一句,您的printf
错误,应定义为\n
或最好main
。
但是(假设您使用的是Linux),请仔细阅读signal(7)(注意有关信号处理程序和异步信号安全功能的说法)和POSIX signal.h
documentation并声明您的int main(void)
标记为
int main(int argc, char**argv)
(或者,在C11中,作为running
)
volatile
qualifier非常重要。否则,允许编译器进行优化(例如,假设volatile sigatomic_t running;
总是为真)。
请注意,使用signal(2)通常是一个坏主意。首先,如果您真的需要信号处理,最好使用sigaction(2)。然后,在您的情况下,对volatile _Atomic bool running;
的调用是无用的(因为running
易失性标志在信号处理程序中已被更改)。最后,对于多路复用输入(&amp;输出),您可以使用poll(2),可用于等待和测试signal(sig, SIG_IGN);
上是否有一些可用输入(实际running
为0 ),更一般地来实现event loops。您可以使用(而不是我强烈推荐的stdin
)旧的和几乎过时的select(2),但您宁愿使用poll(2)。另见epoll(7)&amp; inotify(7)但你可能不需要它们。
请注意,在终端中,STDIN_FILENO
通常是isatty(3)之后的tty(用line discipline检查)(所以某些线路缓冲发生在内部内核)。阅读tty demystified页面。考虑使用GNU readline库和函数(或者ncurses),这可能是您真正需要的。
另请阅读Advanced Linux Programming并养成阅读您正在使用的每个功能的文档的习惯。