C standard versions - MarekBykowski/readme GitHub Wiki

C Standard Versions

Timeline

Standard Year Also known as Key additions
C89 1989 ANSI C, C90 original standard, K&R formalised
C99 1999 ISO C99 stdint.h, stdbool.h, inline, // comments, designated initialisers, VLAs, flexible array members
C11 2011 ISO C11 _Static_assert, _Alignas/_Alignof, <stdatomic.h>, anonymous structs/unions, _Generic
C17 2018 C17, C18 bug fixes only — no new features
C23 2023 ISO C23 constexpr, typeof, nullptr, #embed, bit utilities (<stdbit.h>)

Key Features by Version

C99 — the embedded baseline

#include <stdint.h>       // uint8_t, uint32_t, int64_t etc.
#include <stdbool.h>      // bool, true, false
#include <inttypes.h>     // PRIu32, PRId64 format macros

// Designated initialisers
struct uart_cfg cfg = {
    .baud   = 115200,
    .bits   = 8,
    .parity = false,
};

// inline functions
static inline uint32_t clamp(uint32_t v, uint32_t lo, uint32_t hi) {
    return v < lo ? lo : v > hi ? hi : v;
}

// Mixed declarations and code
for (int i = 0; i < n; i++) { }   // i declared in for loop

// // comments

C11 — the embedded sweet spot

#include <stdatomic.h>

// Compile-time assertions — zero runtime cost
_Static_assert(sizeof(uint32_t) == 4, "uint32_t must be 4 bytes");
_Static_assert(BUFFER_SIZE % 64 == 0, "must be cache-line aligned");

// Explicit alignment
_Alignas(64) uint8_t dma_buf[4096];   // cache-line aligned
size_t a = _Alignof(double);           // query alignment

// Atomics
atomic_int counter = ATOMIC_VAR_INIT(0);
atomic_fetch_add(&counter, 1);
int v = atomic_load_explicit(&counter, memory_order_acquire);

// Anonymous structs/unions
typedef union {
    uint32_t word;
    struct {
        uint8_t b0, b1, b2, b3;   // anonymous struct
    };
} reg32_t;

reg32_t r;
r.word = 0x12345678;
r.b0;   // access byte directly

C23 — not yet mainstream in embedded

// nullptr — unambiguous null pointer constant
int *p = nullptr;

// typeof — like GCC extension, now standard
typeof(x) y = x;

// constexpr for constants
constexpr int MAX = 100;

// #embed — include binary file directly
const uint8_t firmware[] = {
    #embed "firmware.bin"
};

Who Uses What

Project Standard Notes
Linux kernel C11 since kernel 5.18 (2022); heavy GCC extensions
U-Boot C11 follows kernel conventions
FreeRTOS C99 portable, minimal dependencies
ArduPilot C++11/14 C++ not C, but same era
PX4 C++14/17 C++ with modern features
Safety-critical (DO-178, ISO 26262) C99 or C90 certification requires older standards
Typical MCU firmware C99 minimum, C11 preferred

GCC Extensions Used Regardless of Standard

// Attribute — packed, aligned, noreturn, weak, section
__attribute__((packed))
__attribute__((aligned(64)))
__attribute__((noreturn))
__attribute__((section(".ccmram")))

// Built-ins
__builtin_expect(x, 1)        // branch prediction hint
__builtin_popcount(x)         // count set bits
__builtin_clz(x)              // count leading zeros
__builtin_bswap32(x)          // byte swap
__builtin_unreachable()       // dead code hint

// typeof (pre-C23, GCC extension)
typeof(x) tmp = x;

// Compound literals
struct point p = (struct point){.x=1, .y=2};

⚠️ GCC extensions are not portable to MSVC or other compilers — use #ifdef __GNUC__ guards if portability matters.


Compile with Explicit Standard

CFLAGS += -std=c99    # strict C99
CFLAGS += -std=c11    # strict C11
CFLAGS += -std=gnu11  # C11 + GCC extensions (most common for embedded)
CFLAGS += -std=gnu99  # C99 + GCC extensions

# Always add warnings
CFLAGS += -Wall -Wextra -Wpedantic

💡 Most embedded projects use -std=gnu11 — gets C11 features plus GCC extensions like __attribute__ and typeof that embedded code relies on heavily.

⚠️ **GitHub.com Fallback** ⚠️