C99 vs C11 vs C17: What Changed and Which Standard to Use
Short answer: C99 modernised the language, C11 added compile-time checks, generic selection, alignment and atomics and removed gets(), and C17 only fixed defects in C11. For new code, compile with -std=c17 (or -std=c11) and add -pedantic-errors; reach for -std=c99 or -std=c89 only when a toolchain or coding standard requires it.
C89/C90: the baseline
ANSI C (1989), adopted by ISO in 1990, is the oldest standard still selected with -std=c89 or -std=c90. Declarations must appear at the start of a block, only /* */ comments exist, there is no long long and no boolean type, and __STDC_VERSION__ is not defined.
What C99 added
- Declarations mixed with statements, including
for (int i = 0; ...)loop counters. //line comments, designated initializers and compound literals.long long,_Boolwith<stdbool.h>, and fixed-width types in<stdint.h>.inlinefunctions, variable-length arrays andsnprintf.- The
%zu,%tdand%lldconversions forsize_t,ptrdiff_tandlong long.
What C11 added and removed
_Static_assertfor compile-time checks and_Genericfor type-based selection.- Anonymous structures and unions,
_Alignas/_Alignofand_Noreturn. _Atomicwith<stdatomic.h>and<threads.h>; both are optional for implementations.- Variable-length arrays became optional (
__STDC_NO_VLA__). gets()was removed because it cannot limit how much input it stores; usefgets.
What C17 changed
C17, published as ISO/IEC 9899:2018 and also called C18, is a maintenance revision. It adds no language features; it resolves defect reports against C11 and sets __STDC_VERSION__ to 201710L. GCC accepts both -std=c17 and -std=c18. The next revision, C23, is selected with -std=c23 in recent GCC and Clang releases.
Comparison table
| Standard | Document | GCC/Clang flag | __STDC_VERSION__ | Main changes |
|---|---|---|---|---|
| C89/C90 | ANSI X3.159-1989 / ISO/IEC 9899:1990 | -std=c89 | not defined | ANSI C / ISO C90: declarations only at the top of a block, /* */ comments only, no long long. |
| C99 | ISO/IEC 9899:1999 | -std=c99 | 199901L | Mixed declarations, // comments, designated initializers, VLAs, inline, long long, _Bool. |
| C11 | ISO/IEC 9899:2011 | -std=c11 | 201112L | _Generic, _Static_assert, anonymous struct/union, _Alignas, _Noreturn, <stdatomic.h>, threads; gets() removed; VLAs optional. |
| C17 | ISO/IEC 9899:2018 | -std=c17 | 201710L | Defect-fix revision of C11 (also called C18): no new language features, __STDC_VERSION__ becomes 201710L. |
Check which standard your compiler uses
Compile the same file with each flag. With -pedantic-errors, code that needs a newer standard fails to build instead of compiling as an extension.
gcc -std=c89 -pedantic-errors -Wall -Wextra main.c -o main
gcc -std=c99 -pedantic-errors -Wall -Wextra main.c -o main
gcc -std=c11 -pedantic-errors -Wall -Wextra main.c -o main
gcc -std=c17 -pedantic-errors -Wall -Wextra main.c -o mainThis program prints the standard the compiler is using. Built with -std=c17 it prints __STDC_VERSION__ = 201710L.
#include <stdio.h>
int main(void) {
#ifdef __STDC_VERSION__
printf("__STDC_VERSION__ = %ldL\n", __STDC_VERSION__);
#else
puts("__STDC_VERSION__ is not defined (C89/C90)");
#endif
return 0;
}