Catch Ctrl-C en C

¿Cómo se puede capturar Ctrl + C en C?

Con un manejador de señal.

Aquí hay un ejemplo simple que muestra un bool usado en main() :

 #include  static volatile int keepRunning = 1; void intHandler(int dummy) { keepRunning = 0; } // ... int main(void) { signal(SIGINT, intHandler); while (keepRunning) { // ... 

Edite en junio de 2017 : a quién le puede interesar, particularmente a aquellos con un deseo insaciable de editar esta respuesta. Mire, escribí esta respuesta hace siete años. Sí, los estándares de idioma cambian. Si realmente debe mejorar el mundo, por favor agregue su nueva respuesta, pero deje la mía como está. Como la respuesta tiene mi nombre, preferiría que también contenga mis palabras. Gracias.

Chequea aquí:

Nota: Obviamente, este es un ejemplo simple que explica cómo configurar un controlador Ctrl C , pero como siempre hay reglas que deben obedecerse para no romper algo más. Por favor, lea los comentarios a continuación.

El código de muestra de arriba:

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

Adición sobre las plataformas UN * X.

De acuerdo con la página man de signal(2) en GNU / Linux, el comportamiento de la signal no es tan portátil como el comportamiento de sigaction :

El comportamiento de signal () varía según las versiones de UNIX, y también ha variado históricamente en las diferentes versiones de Linux. Evite su uso: use sigaction (2) en su lugar.

En System V, el sistema no bloqueó la entrega de más instancias de la señal y la entrega de una señal restablecería el controlador al predeterminado. En BSD, la semántica cambió.

La siguiente variación de la respuesta anterior de Dirk Eddelbuettel usa sigaction lugar de signal :

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

Configure una trampa (puede atrapar varias señales con un solo controlador):

 señal (SIGQUIT, my_handler);
 señal (SIGINT, my_handler);

Maneje la señal como lo desee, pero tenga en cuenta las limitaciones y las trampas:

 void my_handler (int sig)
 {
   / * Tu código aquí.  * /
 }

O puede poner el terminal en modo raw, así:

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

Ahora debería ser posible leer las teclas Ctrl + C usando fgetc(stdin) . Sin embargo, ten cuidado con usar esto porque no puedes presionar Ctrl + Z , Ctrl + Q , Ctrl + S , etc. como normalmente tampoco.

Con respecto a las respuestas existentes, tenga en cuenta que el manejo de la señal depende de la plataforma. Win32, por ejemplo, maneja muchas menos señales que los sistemas operativos POSIX; mira aquí Mientras SIGINT se declara en signals.h en Win32, consulte la nota en la documentación que explica que no hará lo que cabría esperar.

Esto solo imprime antes de salir.

 #include  #include  #include  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); } 
 #include #include #include 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 función sig_handler comprueba si el valor del argumento pasado es igual al SIGINT, luego se ejecuta printf.