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.
