Table of Contents

stdnoreturn.h

If you have a die() or fatal() function that calls exit, the compiler does not automatically know it never returns. It will warn about missing return values in callers and may generate unnecessary dead-code paths. stdnoreturn.h (C11) defines the noreturn macro — a wrapper around the _Noreturn specifier — which tells the compiler the function will never hand control back to its caller.

#include <stdnoreturn.h>
#include <stdlib.h>
#include <stdio.h>
 
noreturn void die(const char *msg) {
    fprintf(stderr, "fatal: %s\n", msg);
    exit(1);
}
 
int divide(int a, int b) {
    if (b == 0) die("division by zero");
    return a / b;
}

Without noreturn, the compiler might warn that divide has a path that falls off the end without returning a value (after the die call). With it, the compiler knows the die call is a terminal point and the warning goes away. It also opens up better dead-code elimination and can warn you if a noreturn function actually has a reachable return path.

In C23, [[noreturn]] became the standard attribute syntax, and _Noreturn was deprecated. The macro from <stdnoreturn.h> is the C11/C17 portable spelling.

noreturn is distinct from void: void means “returns nothing”; noreturn means “does not return at all”. An infinite loop function should be noreturn void, not just void, so callers do not get spurious warnings.

Practice

// compile: gcc -Wall -o nortest nortest.c
// run: ./nortest
// description: noreturn suppresses the "control reaches end" warning
 
#include <stdnoreturn.h>
#include <stdio.h>
#include <stdlib.h>
 
noreturn void fail(const char *msg) {
    fprintf(stderr, "error: %s\n", msg);
    exit(1);
}
 
int safe_div(int a, int b) {
    if (b == 0) fail("divide by zero");
    return a / b;
}
 
int main(void) {
    printf("%d\n", safe_div(10, 2));   // 5
    printf("%d\n", safe_div(10, 0));   // triggers fail()
    return 0;
}

Remove noreturn from fail and recompile with -Wall. You will likely see a warning about safe_div reaching the end of a non-void function. Adding noreturn back makes the compiler understand that the branch containing fail is a dead end and the warning disappears.