Question Catch-C en C


Comment on attrape Ctrl+C en C?


118
2017-11-18 16:20


origine


Réponses:


Avec un gestionnaire de signal.

Voici un exemple simple en retournant un bool utilisé dans main():

#include <signal.h>

static volatile int keepRunning = 1;

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

// ...

int main(void) {

   signal(SIGINT, intHandler);

   while (keepRunning) { 
      // ...

Modifier en juin 2017: À qui de droit, particulièrement ceux qui ont un besoin insatiable d’éditer cette réponse. Ecoute, j'ai écrit cette réponse Sept il y a des années. Oui, les normes linguistiques changent. Si vous devez vraiment améliorer le monde, veuillez ajouter votre nouvelle réponse mais laisse le mien tel quel. Comme la réponse porte mon nom, je préférerais que cela contienne aussi mes mots. Je vous remercie.


160
2017-11-18 16:20



Vérifier ici:

Remarque: Evidemment, ceci est un exemple simple expliquant juste comment mettre en place un CtrlC gestionnaire, mais comme toujours il y a des règles à respecter pour ne pas casser quelque chose d'autre. Veuillez lire les commentaires ci-dessous.

Le code exemple ci-dessus:

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

42
2017-11-18 16:22



Addendum concernant les plates-formes UN * X.

Selon le signal(2) page de manuel sur GNU / Linux, le comportement de signal n'est pas aussi portable que le comportement de sigaction:

Le comportement de signal () varie selon les versions d'UNIX et a également   historiquement varié à travers différentes versions de Linux. Éviter sa   use: utilise sigaction (2) à la place.

Sur le système V, le système ne bloquait pas la livraison d'autres instances du signal et la remise d'un signal réinitialiserait le gestionnaire par défaut. Dans BSD, la sémantique a changé.

La variation suivante de la réponse précédente de Dirk Eddelbuettel utilise sigaction au lieu de 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
    }
}

24
2017-09-27 20:23



Configurez un piège (vous pouvez piéger plusieurs signaux avec un seul gestionnaire):

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

Manipulez le signal comme bon vous semble, mais soyez conscient des limitations et des pièges:

void my_handler (int sig)
{
  / * Votre code ici. * /
}

10
2017-11-18 16:22



Ou vous pouvez mettre le terminal en mode brut, comme ceci:

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

Maintenant, il devrait être possible de lire Ctrl+C frappes en utilisant fgetc(stdin). Méfiez-vous de cela, car vous ne pouvez pas Ctrl+Z, Ctrl+Q, Ctrl+S, etc. comme d'habitude non plus.


9
2017-11-18 16:37



En ce qui concerne les réponses existantes, notez que le traitement du signal dépend de la plate-forme. Win32 par exemple gère beaucoup moins de signaux que les systèmes d'exploitation POSIX; vois ici. Alors que SIGINT est déclaré dans le fichier signs.h sous Win32, consultez la note dans la documentation qui explique qu’il ne fera pas ce que vous pourriez attendre.


3
2017-11-18 17:18



Ceci imprime juste avant de sortir.

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

2
2017-09-28 16:47



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

La fonction sig_handler vérifie si la valeur de l'argument passé est égale au SIGINT, alors le printf est exécuté.


2
2018-02-08 04:09