What are the key differences between C89/C90, C99, C11, and C17?
The C standard has evolved through several major revisions, each adding important features:
C89/C90 (ANSI C / ISO C): The original standard.
- Function prototypes required.
- Variables must be declared at the start of a block.
- No
//single-line comments (only/* */). - No
inlinekeyword. - No
_Booltype. - No
long longtype. - No variable-length arrays.
C99 (ISO/IEC 9899:1999): Major modernization.
//single-line comments.- Mixed declarations and code (variables anywhere in a block).
inlinefunctions._Booltype (and<stdbool.h>).long long int(at least 64-bit).- Variable-Length Arrays (VLAs).
- Designated initializers:
int a[5] = { [2] = 42 }. - Compound literals:
(struct point){.x = 1, .y = 2}. restrictpointer qualifier.<stdint.h>withuint32_t,int8_t, etc.<inttypes.h>withPRId32,SCNu64format macros.snprintf()(safe formatted output).
C11 (ISO/IEC 9899:2011): Concurrency and safety.
_Generic(type-generic expressions, basis fortgmath.h)._Static_assert(compile-time assertions)._Noreturnfunction specifier._Alignas/_Alignof(alignment control).- Anonymous structs and unions.
<stdatomic.h>(atomic operations).<threads.h>(portable threading).gets()removed (security hazard).- VLAs made optional (implementations can omit them).
C17/C18 (ISO/IEC 9899:2018): Bug-fix release.
- No new features.
- Clarifications and defect fixes from C11.
__STDC_VERSION__=201710L.
C23 (ISO/IEC 9899:2024): Latest standard.
typeofoperator.#embeddirective.- Binary literals (
0b1010). - Digit separators (
1'000'000). nullptrconstant.constexprobjects.
C89: Variables at top of block only. No // comments.
C99: Mixed declarations, //, VLAs, inline, _Bool, stdint.h, restrict.
C11: _Generic, _Static_assert, atomics, threads, anonymous structs.
C17: Bug fixes only. No new features.
C23: typeof, #embed, binary literals, nullptr.
#include <stdio.h>
#include <stdbool.h> /* C99: _Bool as bool */
#include <stdint.h> /* C99: uint32_t, int8_t, etc. */
int main(void) {
/* C89: only block-start declarations */
/* C99: mixed declarations and code */
printf("Hello\n");
int x = 42; /* C99: declaration after statement */
/* C99: // single-line comments */
// This is a C99 comment
/* C99: bool type via stdbool.h */
bool flag = true;
/* C99: long long */
long long big = 9223372036854775807LL;
/* C99: fixed-width integers */
uint32_t val = 0xDEADBEEF;
int8_t byte = -128;
/* Check standard version */
#if __STDC_VERSION__ >= 201710L
printf("C17 or later\n");
#elif __STDC_VERSION__ >= 201112L
printf("C11\n");
#elif __STDC_VERSION__ >= 199901L
printf("C99\n");
#else
printf("C89/C90\n");
#endif
printf("x=%d, flag=%d, big=%lld, val=0x%X, byte=%d\n",
x, flag, big, val, byte);
return 0;
}
- •C99 added mixed declarations, //, VLAs, inline, _Bool, stdint.h, designated initializers, restrict
- •C11 added _Generic, _Static_assert, atomics (stdatomic.h), threads (threads.h), anonymous structs
- •C17 is a bug-fix release with no new features
- •__STDC_VERSION__ macro identifies the standard version at compile time
- •C23 adds typeof, #embed, binary literals, nullptr
- •VLAs are mandatory in C99 but optional in C11+ (MSVC never supported them)
- •C11 threads.h is optional and rarely implemented -- most code uses pthreads instead
- •gets() was removed in C11 -- code using it will not compile under C11+
- •Many embedded compilers only support C99 or even C89 -- check your toolchain's conformance