在C中捕获Ctrl-C

7qhs6swi  于 2023-02-03  发布在  其他
关注(0)|答案(9)|浏览(154)

如何在C中捕获Ctrl+C?

5vf7fwbs

5vf7fwbs1#

有信号处理器。
下面是一个简单的示例,翻转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月编辑 *:给那些可能关心的人,特别是那些有着永不满足的编辑这个答案的冲动的人。看,我在 * 七 * 年前写了这个答案。是的,语言标准改变了。如果你真的想让世界更美好,请添加 * 你的新答案 *,但让我的保持原样。因为答案上有我的名字,我希望它也包含我的话。谢谢。
polkgigr

polkgigr2#

查看此处:

上面的示例代码:

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

ifmq2ha23#

关于UN*X平台的增编。
根据GNU/Linux上的signal(2)手册页,signal的行为不如sigaction的行为可移植:
signal()的行为在不同的UNIX版本中会有所不同,在不同的Linux版本中也会有所不同用途:而是使用sigaction(2)。
在System 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
    }
}
dhxwm5r4

dhxwm5r44#

@Peter Varo更新了Dirk的答案,但Dirk拒绝了修改,以下是Peter的新答案:
虽然上面的代码片段是一个正确的c89示例,但是如果可能的话,应该使用更现代的类型和后续标准提供的保证。因此,对于那些正在寻找符合c99c11的实现的人来说,这里有一个更安全和现代的替代方案:

#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**标头<signal.h>声明了一个类型... sig_atomic_t,它是一个对象的整数类型(可能是volatile-qualified),可以作为原子实体访问,即使存在异步中断。

此外:

    • C11标准:www.example.com § 5如果信号不是作为调用abortraise函数的结果而发生的,则如果信号处理程序引用任何具有static或线程存储持续时间的对象,而不是通过给声明为volatile sig_atomic_t的对象赋值来引用无锁原子对象,则行为是未定义的...7.14.1.1§5If 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 ...
cwtwac6a

cwtwac6a5#

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

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+Z,Ctrl+Q,Ctrl+S等。

x8goxv8g

x8goxv8g6#

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

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

您可以随心所欲地处理信号,但要注意限制和陷阱:

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

mzaanser7#

关于现有的答案,请注意信号处理是依赖于平台的,例如Win32处理的信号比POSIX操作系统少得多;see here。虽然SIGINT是在Win32上的signals. h中声明的,但请参阅文档中的注解,其中解释了SIGINT不会执行您可能期望的操作。

jei2mxaa

jei2mxaa8#

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

lo8azlld

lo8azlld9#

这只是在退出前打印。

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

相关问题