Поймать Ctrl-C в C - PullRequest
       2

Поймать Ctrl-C в C

137 голосов
/ 18 ноября 2010

Как поймать Ctrl + C в C?

Ответы [ 9 ]

184 голосов
/ 18 ноября 2010

с обработчиком сигнала.

Вот простой пример переключения bool, используемого в main():

#include <signal.h>

static volatile int keepRunning = 1;

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

// ...

int main(void) {

   signal(SIGINT, intHandler);

   while (keepRunning) { 
      // ...

Редактировать в июне 2017 г. : Кому это может касаться, особенно тем, у кого ненасытное желание отредактировать этот ответ. Смотри, я написал этот ответ семь лет назад. Да, языковые стандарты меняются. Если вам действительно нужно улучшить мир, пожалуйста, добавьте ваш новый ответ , но оставьте мой как есть. Поскольку в ответе указано мое имя, я бы предпочел, чтобы в нем также содержались мои слова. Спасибо.

42 голосов
/ 18 ноября 2010

Проверьте здесь:

Примечание: Очевидно, это простой пример, объясняющий просто , как настроить обработчик 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
}
28 голосов
/ 28 сентября 2013

Приложение к платформам ООН * Х.

Согласно справочной странице signal(2) в GNU / Linux, поведение signal не так переносимо, как поведение sigaction:

Поведение signal () варьируется в зависимости от версии UNIX, а также исторически различался в разных версиях Linux. Избегайте его используйте: вместо этого используйте sigaction (2).

В System V система не блокировала доставку дальнейших экземпляров сигнала, и доставка сигнала сбросила бы обработчик к стандартному. В BSD семантика изменилась.

В следующем варианте предыдущего ответа Дирка Эддельбюттеля вместо signal используется sigaction:

#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
    }
}
11 голосов
/ 18 ноября 2010

Или вы можете перевести терминал в сырой режим, например:

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

Теперь должно быть возможно прочитать Ctrl + C нажатий клавиш, используя fgetc(stdin). Будьте осторожны, используя это, потому что вы не можете Ctrl + Z , Ctrl + Q , Ctrl + S и т. Д., Как обычно, больше нет.

10 голосов
/ 18 ноября 2010

Настройка ловушки (вы можете перехватить несколько сигналов одним обработчиком):

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

Обрабатывайте сигнал как хотите, но помните об ограничениях и ошибках:

void my_handler (int sig)
{
  /* Your code here. */
}
4 голосов
/ 18 ноября 2010

Относительно существующих ответов, обратите внимание, что обработка сигналов зависит от платформы. Например, Win32 обрабатывает гораздо меньше сигналов, чем операционные системы POSIX; см. Здесь . Хотя SIGINT объявлен в signal.h на Win32, см. Примечание в документации, объясняющее, что он не будет делать то, что вы ожидаете.

3 голосов
/ 08 февраля 2015
#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.

2 голосов
/ 19 января 2019

@ 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 Заголовок <signal.h> объявляет тип ... sig_atomic_t, который является целочисленным типом (возможно, изменчивым) объекта, к которому можно обращаться как к элементарному объекту, даже при наличииасинхронные прерывания.

Более того:

C11 Стандарт: 7.14.1.1§5 Если сигнал возникает не в результате вызова *Функция 1027 * или raise, поведение не определено, если обработчик сигнала ссылается на любой объект с static или продолжительностью хранения потока, который не является атомарным объектом без блокировки, кроме как путем присвоения значения объекту, объявленному как volatile sig_atomic_t ...

2 голосов
/ 28 сентября 2012

Это просто распечатать перед выходом.

#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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...