Article by Ayman Alheraki on February 11 2026 02:18 PM
#include <stddef.h> in C17 and C23
<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.
<stddef.h> contains in C17 (baseline)size_t — “size and length” typeAn 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
void* my_memcpy(void* dst, const void* src, size_t n);Common pitfall
size_t is unsigned: subtracting can underflow.
size_t a = 2, b = 10;size_t diff = a - b; // huge value, not -8ptrdiff_t — “distance between pointers” typeA 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.
ptrdiff_t span(const char* begin, const char* end) { return end - begin;}NULL — the traditional null pointer macroNULL 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.)
offsetof(type, member) — member offset in bytesProduces 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.
struct Node { int x; double y; };
size_t off_y(void) { return offsetof(struct Node, y);}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.
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.)
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”.
<stddef.h>C23 modernizes null pointers by adding:
nullptr and nullptr_tC23 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
void f(void* p);
int main(void) { f(nullptr); // explicitly a null pointer constant nullptr_t x = nullptr; // typed null}NULL may now be defined in terms of nullptrCppreference 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”.
<stddef.h> matters for ABI and low-level correctnessEven 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.
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.