exit-status
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revision | |||
| exit-status [February 23, 2026 at 13:29] – yanevskiv | exit-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 `&& | ||
| + | |||
| + | ## 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: | ||
| + | > ./ | ||
| + | > echo $? | ||
| + | 17 | ||
| + | > echo $? | ||
| + | 0 | ||
| + | */ | ||
| + | #include < | ||
| + | |||
| + | 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 " | ||
| + | |||
| + | ## Constants | ||
| + | The standard C library header [[stdlib.h|< | ||
| + | |||
| + | - `EXIT_SUCCESS` | ||
| + | - `EXIT_FAILURE` | ||
| + | |||
| + | You can find them in `/ | ||
| + | |||
| + | ```c | ||
| + | // $ grep -A 1 -B 3 -e EXIT_FAILURE / | ||
| + | |||
| + | /* We define these the same for all machines. | ||
| + | | ||
| + | #define EXIT_FAILURE | ||
| + | #define EXIT_SUCCESS | ||
| + | ``` | ||
| + | |||
| + | R 0 or 1 | ||
| + | ```c | ||
| + | // Compile: gcc main.c -o my_cat | ||
| + | // Run: | ||
| + | // $ echo "Hello world!" | ||
| + | // $ ./my_cat file.txt | ||
| + | // Hello world! | ||
| + | |||
| + | int main(int argc, char *argv[]) | ||
| + | { | ||
| + | // Check arguments | ||
| + | if (argc != 2) { | ||
| + | fprintf(stderr, | ||
| + | return EXIT_FAILURE; | ||
| + | } | ||
| + | | ||
| + | // Open file | ||
| + | FILE *file = NULL; | ||
| + | if ((file = fopen(argv[1], | ||
| + | fprintf(stderr, | ||
| + | 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(" | ||
| + | } | ||
| + | ``` | ||
| + | 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 | | ||
| + | | ^ | ||
| + | | ; | ||
| + | 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 (" | ||
