ISO/IEC 9899:1999

C99: modern C for systems that have to work.

Ship software with predictable performance, tight control over memory, and a stable standard. C99 adds practical language improvements without turning C into something else.

C99 is ISO/IEC 9899:1999, a widely implemented revision of the C standard.

Why C99 still wins

When latency budgets matter and memory is not negotiable, C remains the language you reach for. C99 keeps the core model intact while standardizing quality-of-life improvements that make real codebases cleaner.

C99 is designed for portability and efficient execution across a wide variety of systems, from tiny embedded targets to high-throughput servers.

Predictable performance

Direct control over layout, allocation, and data representation. You decide what happens on the hot path, and the compiler stays honest.

Portable, standardized power

C99 is a formal standard with a defined library surface area. Your code travels well across compilers and operating systems.

Interoperability by default

C is the common ABI denominator. Calling into other languages, embedding runtimes, and building libraries stays straightforward.

C99 features you will actually use

C99 adds pragmatic language features and library headers that reduce boilerplate and improve clarity while staying close to the machine.

Designated initializers
Initialize structs and arrays by name or index for safer, clearer code.
Compound literals
Create initialized temporary objects without extra declarations.
Mix declarations with statements
Keep variables near usage, reduce scope, improve readability.
stdint.h and inttypes.h
Write portable fixed-width integer code and formatting.
inline, restrict, and improved numeric support
Express intent to the compiler for performance and correctness-oriented optimization.
VLAs and flexible array members (use intentionally)
Model runtime-sized data when the target and toolchain support it.

Code that stays small, fast, and readable

These examples demonstrate common C99 patterns used in production code. They are short on purpose: the goal is clarity, not cleverness.

Designated initializer for safer config objects
#include <stdio.h>

struct server_config {
    const char *host;
    int port;
    int max_clients;
};

int main(void) {
    struct server_config cfg = {
        .host = "127.0.0.1",
        .port = 8080,
        .max_clients = 128
    };

    printf("%s:%d (%d max)\\n", cfg.host, cfg.port, cfg.max_clients);
    return 0;
}

Why this matters: naming fields during initialization guards against ordering mistakes and keeps intent obvious.

Compound literal to pass structured data without ceremony
#include <stdlib.h>
#include <string.h>

struct point { double x, y, z; };

double *store_point(const struct point *p) {
    double *buf = malloc(3 * sizeof(double));
    if (!buf) return NULL;
    memcpy(buf, p, 3 * sizeof(double));
    return buf;
}

int main(void) {
    double *packed = store_point(&(struct point){ .x = 1.0, .y = 0.5, .z = -0.25 });
    free(packed);
    return 0;
}

Why this matters: compound literals keep temporaries localized and reduce boilerplate in allocation-heavy paths.

Portable integer types with stdint.h
#include <stddef.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdio.h>

uint32_t checksum(const uint8_t *data, size_t len) {
    uint32_t sum = 0;
    for (size_t i = 0; i < len; i++) {
        sum += data[i];
    }
    return sum;
}

int main(void) {
    uint8_t payload[] = { 0x01, 0x02, 0x03, 0xFF };
    printf("sum: %" PRIu32 "\\n", checksum(payload, sizeof payload));
    return 0;
}

Why this matters: fixed-width types and format macros make portable IO straightforward across compilers and targets.

Proven in widely used infrastructure

Examples below are factual references to implementation languages or documented requirements, not endorsements.

SQLite

SQLite describes itself as a C-language library implementing an embedded SQL database engine, and states it is the most used database engine in the world.

Redis

Redis states it is written in ANSI C and targets POSIX systems without external dependencies.

Git

Git documentation notes that, as of Git v2.35.0, Git requires C99 (checked via __STDC_VERSION__).

nginx

nginx is widely deployed as a web server and reverse proxy; public references list its primary implementation language as C.

Where C99 shines

Embedded and firmware

Tight memory budgets, deterministic execution, and direct register-level access.

Networking and servers

High throughput, low latency, and explicit control over allocation and data layout.

Databases and storage engines

Cache-aware data structures and predictable IO paths.

Language runtimes and tooling

Build fast parsers, interpreters, and extensions with a stable C interface.

FAQ

What exactly is C99?

C99 refers to ISO/IEC 9899:1999, a revision of the ISO C standard published in 1999. It extends the prior C90-era standard with language and library additions while remaining largely backward compatible.

Is C99 supported by modern compilers?

Most modern toolchains implement the majority of C99; some features have varying support levels depending on the compiler and target. If you need maximum portability, treat a few features (for example, VLAs) as optional and gate them behind build checks.

Will this lock me out of newer standards like C11 or C17?

No. Many codebases choose a baseline standard for portability, then selectively adopt newer features when toolchains and targets allow.

How do I detect C99 in code?

C99 introduced a standard macro __STDC_VERSION__ value of at least 199901L for C99 support, which some projects use in their build and coding guidelines.

Adopt a standard that respects the hardware.

Use C99 as a clean baseline for portable systems code. Keep your dependencies lean, your binaries small, and your performance predictable.