Table of Contents

Exit status

Exit status lets the user of your program know if the program ended in success or failure.

Commonly, 0 is success, any other value is failure (most commonly, failure is 1 – a bit counter intuitive at first!)

Your users can inspect it with echo $? after your program ends. Thanks to the exit status, your user can chain program with other programs using && and put your program in if [ ... ]; then ... fi statements when they write shell scripts.

Echo

When you run a program, the shell remembers the exit status in the $? variable. You can inspect that variable with echo $?. The echo command is going to replace the value of $? with its own exit status (likely a success)

Here's a simple prog

/*
Compile: gcc main.c -o exit_status
Shell:
    > ./exit_status 17
    > echo $?
      17
    > echo $?
      0
*/
#include <stdlib.h>
 
int main(int argc, char *argv[])
{
    return (argc == 2 ? atoi(argv[1]) : EXIT_FAILURE);
}

The program itself prints nothing – but the shell remembers the exit status of the last program in $? variable. The shell expands the variable, gives the value “17” to the echo commands, the echo commands prints “17”, and then returns the value 0 to the shell. The shell then remembers “0” in $? variable.

Constants

The standard C library header <stdlib.h> provides the following the following constants two constants:

You can find them in /usr/include/stdlib.h with grep command (-A means “lines after”, -B means “lines before”, -e means “expression”)

// $ grep -A 1 -B 3 -e EXIT_FAILURE /usr/include/stdlib.h
 
/* We define these the same for all machines.
   Changes from this to the outside world should be done in `_exit'.  */
#define EXIT_FAILURE    1       /* Failing exit status.  */
#define EXIT_SUCCESS    0       /* Successful exit status.  */

R 0 or 1

// Compile: gcc main.c -o my_cat
// Run:
//   $ echo "Hello world!" > file.txt
//   $ ./my_cat file.txt
//   Hello world!
 
int main(int argc, char *argv[])
{
    // Check arguments
    if (argc != 2) {
        fprintf(stderr, "Error: Expected one. argument");
        return EXIT_FAILURE;
    }
 
    // Open file
    FILE *file = NULL;
    if ((file = fopen(argv[1], "r")) == NULL) {
        fprintf(stderr, "Error: Can't open file '%s' for reading", file);
        return EXIT_FAILURE;
    }
 
    // Read and print chars
    int ch;
    while ((ch = fgetc(file)) != EOF) {
        putchar(ch);
    }
 
    // Close file
    fclose(file);
 
    // Return success
    return EXIT_SUCCESS;
}

Why is 0 success?

In C programming language, zero is considered false. What's funny is that if you use EXIT_SUCCESS in an if-statement directly the if-block is skipped – because EXIT_SUCCESS is defined as 0!

if (EXIT_SUCCESS) {
    printf("This never prints...");
}

So why is EXIT_SUCCESS defined as 0?

That's because the original intent of exit status was

#define SUCCESS 0
#define FAILURE_ONE 1
#define FAILURE_TWO 2
...
#define FAILURE_LAST 255
 
int main()
{
    if (/*... something goes wrong 1 ...*/)
        return FAILURE_ONE;
    if (/*... something goes wrong 2 ...*/)
        return FAILURE_TWO;
    return SUCCESS;
}

But there are way more than 255 ways a program can fail – and it's much better if you get a descriptive error in stderr instead of a single number.

Think about it! If you forget a semicolon – would you rather the compiler tell where exactly? Or would you rather it tell you something cryptic “Error code: 233”?

That's why, when most programs fail, they print a detailed report in stderr but return EXIT_FAILURE which is defined as 1.

 $ gcc main.c -o program
main.c: In function ‘main’:
main.c:5:26: error: expected ‘;’ before ‘}’ token
    5 |     printf("Hello world")
      |                          ^
      |                          ;
    6 | }
      | ~
 $ echo $?
1

Exit status: 130

When a program is interrupted by a signal the exit status

exit_status = 128 + signal_number

Ctrl + A = 128
Ctrl + B = 129
Ctrl + C = 130
... and so on ...

When you cancel a program with Ctrl + C, you're sending SIGINT signal (“signal interrupt”) to the program which interrupts its execution and the value of $? is going to say 130.