Logo
Articles Compilers Libraries Books MiniBooklets Assembly C++ Rust Linux CPU Others Videos
Advertisement

Article by Ayman Alheraki on February 11 2026 02:18 PM

Inside #include stddef.h in C17 and C23

Inside #include <stddef.h> in C17 and C23

 

What it really contains, why it exists, and why systems programmers treat it as “bedrock”

<stddef.h> is not a “utility header”. It’s one of the core vocabulary headers of C: it standardizes the small set of types and macros that make low-level, portable C code possible—sizes, pointer differences, alignment, null pointers, and member offsets.

If you write allocators, containers, parsers, ABIs/FFI layers, kernels, runtimes, or compiler-adjacent code, you’re using <stddef.h>—directly or indirectly.

1) What <stddef.h> contains in C17 (baseline)

1.1 size_t — “size and length” type

  • An unsigned integer type used to represent sizes and counts in memory.

  • It’s the type of sizeof results and is used pervasively in APIs that deal with memory and buffers.

Why it matters

  • On 64-bit systems, size_t is typically 64-bit; using unsigned int for lengths can break for large objects or large indexing.

Typical usage

Common pitfall

  • size_t is unsigned: subtracting can underflow.

1.2 ptrdiff_t — “distance between pointers” type

  • A signed integer type for pointer subtraction results (difference between two pointers to elements in the same array object).

Why it matters

  • When you compute end - begin, you want a signed type that matches the platform’s address model.

1.3 NULL — the traditional null pointer macro

  • NULL is an implementation-defined null pointer constant.

  • Historically it can be 0, 0L, or (void*)0 depending on the platform and headers.

Why systems programmers care

  • In C, NULL being “an integer 0” is legal, but it can cause subtle issues in:

    • varargs (...) calls

    • _Generic dispatch

    • APIs where you want “this is definitely a pointer-null” rather than “integer zero that converts” (And this is exactly part of what C23 improves.)

1.4 offsetof(type, member) — member offset in bytes

  • Produces the byte offset of a struct member within its enclosing type.

  • Extremely useful for intrusive data structures, serialization boundaries (when used carefully), and low-level layout work.

Important caution

  • offsetof is only well-defined for valid member designators in standard-layout struct types; using it on bit-fields or doing “clever” UB tricks is a classic pitfall.

1.5 wchar_t — wide character type (C header behavior)

In practice, C’s <stddef.h> is one of the places where wchar_t is declared on many implementations; and we have a strong standards hint for this: C++’s <cstddef> explicitly says it is the same as C’s <stddef.h> except that it does *not* declare wchar_t, which implies C’s <stddef.h> does.

(So, from a portability standpoint: treat wchar_t as a “common definition” type that may appear via <stddef.h> in C ecosystems, but always include the correct headers for your usage style.)

1.6 max_align_t — “alignment strong enough for any scalar” (present in C17)

  • Added in C11, so it is part of C17.

  • A type whose alignment is at least as strict as any scalar type on the platform.

Why it matters

  • If you build an allocator or arena, you often want to guarantee “this buffer is aligned enough for anything”.

2) What changes in C23 inside <stddef.h>

C23 modernizes null pointers by adding:

2.1 nullptr and nullptr_t

  • C23 introduces a predefined null pointer constant nullptr and its type nullptr_t via <stddef.h>.

This addresses long-standing problems where NULL might be an integer constant and not a dedicated null pointer entity.

C23 usage

2.2 NULL may now be defined in terms of nullptr

Cppreference notes that since C23, NULL can be defined as the predefined constant nullptr. That means C23 gives implementations a cleaner way to make NULL “actually pointer-null” instead of “integer zero”.

3) Why <stddef.h> matters for ABI and low-level correctness

Even though <stddef.h> looks small, it defines the vocabulary used in binary contracts:

  • size_t leaks into public APIs (buffer sizes, lengths). Its width depends on the platform data model (32 vs 64).

  • ptrdiff_t reflects pointer arithmetic semantics and address space realities.

  • max_align_t shapes allocator guarantees and correct alignment in low-level storage.

  • C23’s nullptr / nullptr_t improves correctness and clarity at boundaries (especially with varargs and generic selection).

If you’re designing a stable ABI, you don’t “casually” use these—you document what they mean on your target ABIs.

4) A practical “systems-grade” mental model

Think of <stddef.h> as the header that standardizes:

  • How big things can be (size_t)

  • How far pointers are apart (ptrdiff_t)

  • How to describe null (C17: NULL, C23: nullptr + nullptr_t)

  • How to reason about layout (offsetof)

  • How to guarantee alignment (max_align_t)

  • How wide characters are represented (wchar_t in C header practice)

This is why you find it at the heart of allocators, container libraries, kernels, runtimes, and FFI design.

Advertisements

Responsive Counter
General Counter
1166461
Daily Counter
857