devnotes.

Modern C Features: C11 and C17

C11 (2011) was the first major update to C since C99, adding several features that improved type safety and compile-time checking, and C17 (2018) followed mainly as a bugfix release with no new features.

#include <assert.h>

_Static_assert(sizeof(int) == 4, "This code assumes a 4-byte int");

#define TYPE_NAME(x) _Generic((x), \
    int: "int", \
    float: "float", \
    double: "double", \
    default: "other")

int main(void) {
    int i = 5;
    double d = 3.14;
    printf("%s\n", TYPE_NAME(i)); // "int"
    printf("%s\n", TYPE_NAME(d)); // "double"

    struct Point {
        int x, y;
        struct { int r, g, b; }; // anonymous struct — members accessed directly
    } p;
    p.x = 1;
    p.r = 255; // no intermediate name needed, thanks to the anonymous struct

    return 0;
}

_Static_assert (usable via the friendlier static_assert macro from <assert.h>) checks a condition at compile time, immediately failing the build with a custom message if it's false — useful for catching assumptions (like a specific type's size) that would otherwise only surface as a confusing runtime bug on an unusual platform.

_Generic (the type-generic selection expression) lets a macro branch on the type of its argument at compile time, which is how TYPE_NAME above picks a different string literal depending on whether it's given an int or a double — this is the mechanism behind much of <tgmath.h>, which picks the right math function (sinf, sin, sinl) automatically based on argument type.

C11 also added anonymous structs and unions (members accessed as if they belonged directly to the enclosing struct, as with p.r above), a standard threading API (<threads.h>, though in practice many projects still prefer POSIX threads or platform-specific APIs for better tooling support), and <stdalign.h> for controlling memory alignment explicitly.

Modern C Features: C11 and C17 Explained | DevNotes