在 C 中捕获 Ctrl-C

发布于 2024-10-03 08:26:05 字数 47 浏览 2 评论 0原文

如何在 C 中捕捉 Ctrl+C

How does one catch Ctrl+C in C?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

尘世孤行 2024-10-10 08:26:05

使用信号处理程序。

下面是一个翻转 main() 中使用的 bool 的简单示例:

#include <signal.h>

static volatile int keepRunning = 1;

void intHandler(int dummy) {
    keepRunning = 0;
}

// ...

int main(void) {

   signal(SIGINT, intHandler);

   while (keepRunning) { 
      // ...

2017 年 6 月编辑:它可能涉及的对象,特别是那些拥有编辑这个答案的强烈冲动。看,我年前写了这个答案。是的,语言标准发生了变化。如果您确实必须让世界变得更好,请添加您的新答案,但保留我的原样。由于答案上有我的名字,我希望它也包含我的话。谢谢。

With a signal handler.

Here is a simple example flipping a bool used in 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 seven years ago. Yes, language standards change. If you really must better the world, please add your new answer but leave mine as is. As the answer has my name on it, I'd prefer it to contain my words too. Thank you.

烟火散人牵绊 2024-10-10 08:26:05

检查此处:

注意:显然,这是一个简单的示例,只是解释如何设置Ctrl+C 处理程序,但一如既往,需要遵守一些规则,以免破坏其他内容。请阅读下面的评论。

上面的示例代码:

#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
}

Check here:

Note: Obviously, this is a simple example explaining just how to set up a Ctrl+C handler, but as always there are rules that need to be obeyed in order not to break something else. Please read the comments below.

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
}
耀眼的星火 2024-10-10 08:26:05

关于 UN*X 平台的附录。

根据 GNU/Linux 上的 signal(2) 手册页,signal 的行为不如 sigaction 的行为可移植:

signal() 的行为因 UNIX 版本而异,并且也
不同版本的 Linux 历史上有所不同。避免其
使用:使用 sigaction(2) 代替。

在系统 V 上,系统不会阻止进一步发送信号实例,并且发送信号会将处理程序重置为默认处理程序。在 BSD 中,语义发生了变化。

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
    }
}

Addendum regarding UN*X platforms.

According to the signal(2) man page on GNU/Linux, the behavior of signal is not as portable as behavior of 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.

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.

The following variation of previous answer by Dirk Eddelbuettel uses sigaction instead of 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
    }
}
清泪尽 2024-10-10 08:26:05

@Peter Varo 更新了德克的答案,但德克拒绝了更改。这是彼得的新答案:

虽然上面的代码片段是正确的 例如,如果可能的话,应该使用后来的标准提供的更现代的类型和保证。因此,对于那些正在寻找 符合实施:

#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 标准:7.14§2 标头 声明一个类型 ... sig_atomic_t 这是(可能是即使存在异步中断,也可以将对象作为原子实体进行访问(易失性限定)整数类型。

此外:

C11 标准:7.14.1.1§5 如果信号不是由于调用 abortraise 函数而发生的,则如果信号处理程序引用任何具有静态或线程存储持续时间的对象,该对象不是无锁原子对象,而不是通过将值分配给声明为 volatile sig_atomic_t< 的对象,则行为未定义/代码>...

@Peter Varo updated Dirk's answer, but Dirk rejected the change. Here's the new answer by Peter:

Although the above snippet is a correct example, 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 and conforming implementation:

#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§2 The header <signal.h> declare a type ... sig_atomic_t which 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.

Furthermore:

C11 Standard: 7.14.1.1§5 If the signal occurs other than as the result of calling the abort or raise function, the behavior is undefined if the signal handler refers to any object with static or thread storage duration that is not a lock-free atomic object other than by assigning a value to an object declared as volatile sig_atomic_t...

天气好吗我好吗 2024-10-10 08:26:05

或者您可以将终端置于原始模式,如下所示:

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);

现在应该可以使用 fgetc(stdin) 读取 Ctrl+C 击键。但要小心使用它,因为你不能 Ctrl+ZCtrl+QCtrl< /kbd>+S 等也像平常一样。

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+C keystrokes using fgetc(stdin). Beware using this though because you can't Ctrl+Z, Ctrl+Q, Ctrl+S, etc. like normally any more either.

万水千山粽是情ミ 2024-10-10 08:26:05

设置陷阱(您可以使用一个处理程序捕获多个信号):

signal (SIGQUIT, my_handler);
signal (SIGINT, my_handler);

按照您想要的方式处理信号,但要注意限制和陷阱:

void my_handler (int sig)
{
  /* Your code here. */
}

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. */
}
帅的被狗咬 2024-10-10 08:26:05

关于现有答案,请注意信号处理取决于平台。例如,Win32 处理的信号比 POSIX 操作系统少得多; 请参阅此处。虽然 SIGINT 在 Win32 上的 Signals.h 中声明,但请参阅文档中的注释,说明它不会执行您可能期望的操作。

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.

早乙女 2024-10-10 08:26:05
#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;
}

函数 sig_handler 检查传递的参数值是否等于 SIGINT,然后执行 printf。

#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.

只有影子陪我不离不弃 2024-10-10 08:26:05

这只是在退出之前打印。

#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);
}

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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文