Site Tools


exit-status

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
exit-status [February 19, 2026 at 16:07] yanevskivexit-status [May 14, 2026 at 11:38] (current) – external edit 127.0.0.1
Line 1: Line 1:
 +# 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
 +```c
 +/*
 +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|<stdlib.h>]] provides the following the following constants two constants:
 +
 + - `EXIT_SUCCESS`
 + - `EXIT_FAILURE`
 +
 +You can find them in `/usr/include/stdlib.h` with grep command (-A means "lines after", -B means "lines before", -e means "expression")
 +
 +```c
 +// $ 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
 +```c
 +// 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!
 +```c
 +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 
 +```c
 +#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.
 +```bash
 + $ 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.