176

How does one catch Ctrl+C in C?

Mojtaba Ahmadi
  • 802
  • 12
  • 32
Feldor
  • 1,771
  • 2
  • 11
  • 4
  • 5
    There's no such thing as catching signals in C.... or at least so I thought until I read the C99 standard. It turns out that there is signal handling defined in C but Ctrl-C isn't mandated to produce any specific signal or a signal at all. Depending on your platform, this might be impossible. – JeremyP Nov 18 '10 at 16:40
  • 1
    Signal handling is mostly implementation dependent. On *nix platforms, use , and if you're on OSX you can take advantage of GCD to make things even easier~. – Dylan Lukes Nov 18 '10 at 19:09

9 Answers9

226

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.

Vojislav Stojkovic
  • 7,735
  • 4
  • 33
  • 47
Dirk Eddelbuettel
  • 331,520
  • 51
  • 596
  • 675
  • Fair enough but the question was on Ctrl-C and it answers this -- so no need to downvote. – Dirk Eddelbuettel Nov 18 '10 at 16:33
  • But I will update the code I took this from -- so kudos. I do appreciate the correction. – Dirk Eddelbuettel Nov 18 '10 at 16:45
  • @larsman: Actually, the C standard states that whether a signal can be caught is entirely up to the implementation. Thus it is conceivable that on a particular platform SIGKILL can be caught. So I am upvoting to counteract your erroneous down vote. – JeremyP Nov 18 '10 at 16:46
  • 2
    Let's mention that we need to #include for this to work! – kristianlm Sep 04 '11 at 14:36
  • 1
    How about `#include `? :) – Mazze Dec 14 '12 at 12:23
  • 13
    static It should be `bool volatile keepRunning = true;` to be 100% safe. The compiler is free to cache `keepRunning` in a register and the volatile will prevent this. In practice it may most likely also work without the volatile keyword when the while loop calls at least one non-inline function. – Johannes Overmann May 20 '13 at 11:05
  • @puk: Ooops, could be -- my context is often C++ not ANSI C. – Dirk Eddelbuettel Nov 12 '13 at 22:29
  • 1
    @DirkEddelbuettel umm.. what's wrong with it? your original intention was using a `bool` -- which I completely agree with, even if its only purpose is to clearly communicate your intentions with that state -- and the previous edit was not only incomplete (your second sentence still talked about the type `bool`) but was also unnecessary, as C does have a `bool`/`_Bool` type. Also adding the explicit bypassing instructions for the signal-handler makes it easier for the reader and the compiler to understand your intentions with that argument.. – Peter Varo May 18 '17 at 22:16
  • I felt the criticism of not using bool (ie no c99) was valid, and the answer you chose to override/edit without consultation was also valid. So why muck with it? If you must make an improvement, post a new answer. Now my answers reflects something I did not write. Not ideal. – Dirk Eddelbuettel May 18 '17 at 22:19
  • 2
    @DirkEddelbuettel I stand corrected, I thought my improvements will reflect your original intentions more, sorry if that did not happen. Anyway, the greater issue is that, since your answer tries to be generic enough, and because IMO it should provide a snippet that is also working under asynchronous interrupts: I would either use `sig_atomic_t` or `atomic_bool` types there. I just missed that one. Now, since we are talking: would you like me to rollback my latest edit? No hard feelings there it would be perfectly understandable from your point of view :) – Peter Varo May 18 '17 at 22:51
  • I like that this constructive :) I think rolling back `bool` to `int` (for real old C) is fine; I hear you on catching the interrupt. Maybe we can meet half-way and improve on both? – Dirk Eddelbuettel May 19 '17 at 02:55
  • 1
    Right, so I rolled it back for now, and I would like to extend it, with a new section: that is, your answer would have two sections: [tag:C89] and [tag:C99]/[tag:C11] parts, and in the latter, I would use the atomic type. In this case your answer would be helpful for basically anyone in the C world, who tries to deal with `signal.h` and wants to use a conforming implementation. – Peter Varo May 19 '17 at 07:48
  • 2
    That is much better! – Dirk Eddelbuettel May 19 '17 at 10:59
  • 2
    @JohannesOvermann Not that I want to nitpick but strictly speaking, it doesn't matter if the code calls any non-inline functions or not, as only when crossing a memory barrier the compiler is not allowed to rely on a cached value. Locking/Unlocking a mutex would be such a memory barrier. As the variable is static and thus not visible outside the current file, the compiler is safe to assume that a function cannot ever change its value, unless you pass a reference to that variable to the function. So volatile is strongly advised here in any case. – Mecki Jul 11 '18 at 17:22
  • An [updated version](https://stackoverflow.com/a/54267342/8061009) of this answer has been added (by MCCCS) for the newer c standards. – Will Jan 31 '19 at 21:14
  • 1
    Line 1 of this answer really should say **"With a signal handler to process the `SIGINT` interrupt signal"**, instead of just "With a signal handler." This would help the clarity of this answer, as linux's signum.h file has 31 signals, with SIGINT being just *one* of them. – Gabriel Staples Oct 31 '19 at 22:10
48

Check here:

Note: Obviously, this is a simple example explaining just how to set up a CtrlC 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
}
Vukašin Manojlović
  • 2,495
  • 2
  • 19
  • 26
icyrock.com
  • 25,648
  • 4
  • 58
  • 78
  • 2
    @Derrick Agree, `int main` is a proper thing, but `gcc` and other compilers compile this to a correctly running programs since 1990's. Explained pretty well here: http://www.eskimo.com/~scs/readings/voidmain.960823.html - it's basically a "feature", I take it like that. – icyrock.com Nov 18 '10 at 16:32
  • 2
    @icyrock.com: All very true (regarding void main() in C), but when posting publicly it is probably as well to avoid the debate altogether by using int main() lest it distract from teh main point. – Clifford Nov 18 '10 at 17:08
  • 23
    There is a huge flaw in this. You cannot safely use printf within the content of a signal handler. It's a violation of asynchronous signal safety. This is because printf is not reentrant. What happens if the program was in the middle of using printf when Ctrl-C was pressed, and your signal handler starts using it at the same time? Hint: It will likely break. write and fwrite are same to use in this context. – Dylan Lukes Nov 18 '10 at 19:07
  • @icyrock.com: It may compile it but it is still wrong and can generate problems for others: http://users.aber.ac.uk/auj/voidmain.shtml – Martin York Nov 18 '10 at 19:49
  • 2
    @icyrock.com: Doing anything complicated in a signal handler is going to cause headaches. Especially using the io system. – Martin York Nov 18 '10 at 19:50
  • @Dylan, @Martin Thanks for the additional comments, I edited to note this for others reading the code. – icyrock.com Nov 18 '10 at 22:33
  • 2
    @stacker Thanks - I think it's worth it at the end. If somebody stumbles across this code in the future, better to have it right as much as possible, regardless of the topic of the question. – icyrock.com Nov 18 '10 at 23:10
  • `#include ` needs to be added for `pause()` to work. – Deanie Jan 02 '19 at 05:11
32

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
    }
}
Filip J.
  • 565
  • 6
  • 10
  • 3
    [Needs to be `volatile sig_atomic_t` to be well-defined](https://stackoverflow.com/questions/37631153/how-to-clean-up-local-data-in-sigint-handler#comment62744362_37631288) – Eric Jan 04 '18 at 21:43
14

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.

Ulf Gjerdingen
  • 1,326
  • 3
  • 15
  • 20
Walter
  • 793
  • 5
  • 7
14

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

MCCCS
  • 898
  • 1
  • 17
  • 37
11

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. */
}
Paul Beckingham
  • 13,460
  • 5
  • 30
  • 67
5

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.

Clifford
  • 76,825
  • 12
  • 79
  • 145
3
#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.

Love Bisaria
  • 147
  • 12
2

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);
}
alemol
  • 6,344
  • 1
  • 18
  • 27