C语言 在 C 中捕捉 Ctrl-C
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4217037/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Catch Ctrl-C in C
提问by Feldor
How does one catch Ctrl+Cin C?
如何在 C 中捕获Ctrl+ C?
回答by Dirk Eddelbuettel
With a signal handler.
带有信号处理程序。
Here is a simple example flipping a boolused in main():
这是一个简单的示例,bool用于翻转in 中使用的 a main():
#include <signal.h>
static volatile int keepRunning = 1;
void intHandler(int dummy) {
keepRunning = 0;
}
// ...
int main(void) {
signal(SIGINT, intHandler);
while (keepRunning) {
// ...
Edit in June 2017: To whom it may concern, particularly those with an insatiable urge to edit this answer. Look, I wrote this answer sevenyears ago. Yes, language standards change. If you really must better the world, please add your new answerbut leave mine as is. As the answer has my name on it, I'd prefer it to contain my words too. Thank you.
2017 年 6 月编辑:它可能关注的对象,尤其是那些急于编辑此答案的人。看,我七年前写了这个答案。是的,语言标准发生了变化。如果您真的必须改善世界,请添加您的新答案,但保留我的原样。由于答案上有我的名字,我希望它也包含我的话。谢谢你。
回答by icyrock.com
Check here:
检查这里:
Note:Obviously, this is a simple example explaining justhow to set up a CtrlChandler, but as always there are rules that need to be obeyed in order not to break something else. Please read the comments below.
注意:显然,这是一个简单的例子,解释了如何设置CtrlC处理程序,但一如既往,为了不破坏其他东西,需要遵守一些规则。请阅读下面的评论。
The sample code from above:
上面的示例代码:
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
void INThandler(int);
int main(void)
{
signal(SIGINT, INThandler);
while (1)
pause();
return 0;
}
void INThandler(int sig)
{
char c;
signal(sig, SIG_IGN);
printf("OUCH, did you hit Ctrl-C?\n"
"Do you really want to quit? [y/n] ");
c = getchar();
if (c == 'y' || c == 'Y')
exit(0);
else
signal(SIGINT, INThandler);
getchar(); // Get new line character
}
回答by Filip J.
Addendum regarding UN*X platforms.
关于 UN*X 平台的附录。
According to the signal(2)man page on GNU/Linux, the behavior of signalis not as portable as behavior of sigaction:
根据signal(2)GNU/Linux 上的手册页, 的行为signal不如 的行为可移植sigaction:
The behavior of signal() varies across UNIX versions, and has also varied historically across different versions of Linux. Avoid its use: use sigaction(2) instead.
signal() 的行为因 UNIX 版本而异,并且在历史上也因 Linux 的不同版本而异。避免使用它:改用 sigaction(2)。
On System V, system did not block delivery of further instances of the signal and delivery of a signal would reset the handler to the default one. In BSD the semantics changed.
在 System V 上,系统不会阻止信号的其他实例的传递,并且信号的传递会将处理程序重置为默认处理程序。在 BSD 中,语义发生了变化。
The following variation of previous answer by Dirk Eddelbuettel uses sigactioninstead of signal:
Dirk Eddelbuettel 对先前答案的以下变体使用sigaction代替signal:
#include <signal.h>
#include <stdlib.h>
static bool keepRunning = true;
void intHandler(int) {
keepRunning = false;
}
int main(int argc, char *argv[]) {
struct sigaction act;
act.sa_handler = intHandler;
sigaction(SIGINT, &act, NULL);
while (keepRunning) {
// main loop
}
}
回答by Walter
Or you can put the terminal in raw mode, like this:
或者您可以将终端置于原始模式,如下所示:
struct termios term;
term.c_iflag |= IGNBRK;
term.c_iflag &= ~(INLCR | ICRNL | IXON | IXOFF);
term.c_lflag &= ~(ICANON | ECHO | ECHOK | ECHOE | ECHONL | ISIG | IEXTEN);
term.c_cc[VMIN] = 1;
term.c_cc[VTIME] = 0;
tcsetattr(fileno(stdin), TCSANOW, &term);
Now it should be possible to read Ctrl+Ckeystrokes using fgetc(stdin). Beware using this though because you can't Ctrl+Z, Ctrl+Q, Ctrl+S, etc. like normally any more either.
现在,应该是可以读Ctrl+C使用按键fgetc(stdin)。小心使用它,因为你不能像平常那样Ctrl+ Z、Ctrl+ Q、Ctrl+S等。
回答by Paul Beckingham
Set up a trap (you can trap several signals with one handler):
设置陷阱(您可以使用一个处理程序捕获多个信号):
signal (SIGQUIT, my_handler); signal (SIGINT, my_handler);
Handle the signal however you want, but be aware of limitations and gotchas:
随心所欲地处理信号,但要注意限制和陷阱:
void my_handler (int sig)
{
/* Your code here. */
}
回答by MCCCS
@Peter Varoupdated Dirk's answer, but Dirk rejected the change. Here's the new answer by Peter:
@Peter Varo更新了 Dirk 的回答,但 Dirk 拒绝了更改。这是彼得的新答案:
Although the above snippet is a correct c89example, one should use the more modern types and guarantees provided by the later standards if possible. Therefore, here is a safer and modern alternative for those who are seeking for the c99and c11conforming implementation:
虽然上面的代码片段是一个正确的c89示例,但如果可能的话,应该使用较新的类型和更高标准提供的保证。因此,对于那些寻求符合c99和c11 的实现的人来说,这是一个更安全、更现代的替代方案:
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
static volatile sig_atomic_t keep_running = 1;
static void sig_handler(int _)
{
(void)_;
keep_running = 0;
}
int main(void)
{
signal(SIGINT, sig_handler);
while (keep_running)
puts("Still running...");
puts("Stopped by signal `SIGINT'");
return EXIT_SUCCESS;
}
C11 Standard: 7.14§2The header
<signal.h>declare a type ...sig_atomic_twhich is the (possibly volatile-qualified) integer type of an object that can be accessed as an atomic entity, even in the presence of asynchronous interrupts.
C11 标准:7.14§2标头
<signal.h>声明了一个类型......sig_atomic_t它是一个对象的(可能是 volatile 限定的)整数类型,即使存在异步中断,也可以作为原子实体访问。
Furthermore:
此外:
C11 Standard: 7.14.1.1§5If the signal occurs other than as the result of calling the
abortorraisefunction, the behavior is undefined if the signal handler refers to any object withstaticor thread storage duration that is not a lock-free atomic object other than by assigning a value to an object declared asvolatile sig_atomic_t...
C11 标准:7.14.1.1§5如果信号不是作为调用
abortorraise函数的结果而发生的,则如果信号处理程序引用任何具有static或线程存储持续时间不是无锁原子对象的对象,则行为未定义而不是通过为声明为volatile sig_atomic_t...的对象赋值
回答by Clifford
Regarding existing answers, note that signal handling is platform dependent. Win32 for example handles far fewer signals than POSIX operating systems; see here. While SIGINT is declared in signals.h on Win32, see the note in the documentation that explains that it will not do what you might expect.
关于现有答案,请注意信号处理取决于平台。例如,Win32 处理的信号比 POSIX 操作系统少得多;看到这里。虽然 SIGINT 是在 Win32 上的signals.h 中声明的,但请参阅文档中的注释,说明它不会执行您所期望的操作。
回答by Love Bisaria
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
void sig_handler(int signo)
{
if (signo == SIGINT)
printf("received SIGINT\n");
}
int main(void)
{
if (signal(SIGINT, sig_handler) == SIG_ERR)
printf("\ncan't catch SIGINT\n");
// A long long wait so that we can easily issue a signal to this process
while(1)
sleep(1);
return 0;
}
The function sig_handler checks if the value of the argument passed is equal to the SIGINT, then the printf is executed.
函数 sig_handler 检查传递的参数值是否等于 SIGINT,然后执行 printf。
回答by alemol
This just print before exit.
这只是在退出前打印。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void sigint_handler(int);
int main(void)
{
signal(SIGINT, sigint_handler);
while (1){
pause();
}
return 0;
}
void sigint_handler(int sig)
{
/*do something*/
printf("killing process %d\n",getpid());
exit(0);
}

