# stddef.h `size_t`, `NULL`, `offsetof` — you have seen these in practically every C codebase. They all come from **`stddef.h`**, which defines the handful of fundamental types and macros that the rest of the standard library depends on. Most headers pull it in transitively, so you often get it without including it directly. The main definitions: ```c #include size_t n = sizeof(int); // unsigned type for sizes and counts; result of sizeof ptrdiff_t d = p2 - p1; // signed type for pointer differences wchar_t wc = L'A'; // wide character type (platform-dependent width) max_align_t; // type with the strictest alignment of any standard type NULL // null pointer constant offsetof(struct s, member) // byte offset of member within struct s ``` `size_t` is the right type for array indices, loop counters over arrays, and anything produced by `sizeof`. It is unsigned and wide enough to hold the size of any object (32 bits on 32-bit platforms, 64 on 64-bit). Using `int` for array indices can produce sign-comparison warnings and wrong results when arrays exceed 2 GB. `ptrdiff_t` is the type you get when subtracting two pointers within the same array. It is signed, so `p2 - p1` can be negative if `p2` precedes `p1`. `offsetof` tells you where a struct member sits within the struct. It is used in serialisation, memory-mapped hardware register layouts, and the `container_of` pattern common in Linux kernel code: ```c struct point { int x; int y; }; offsetof(struct point, y) // typically 4 (after the 4-byte x) ``` ## Practice ```c // compile: gcc -o deftest deftest.c // run: ./deftest // description: print sizes and offsets for a packed-ish struct #include #include struct packet { uint8_t type; uint16_t length; uint32_t checksum; }; int main(void) { printf("sizeof(struct packet) = %zu\n", sizeof(struct packet)); printf("offsetof type = %zu\n", offsetof(struct packet, type)); printf("offsetof length = %zu\n", offsetof(struct packet, length)); printf("offsetof checksum = %zu\n", offsetof(struct packet, checksum)); return 0; } ``` The offsets will likely be 0, 2, and 4 due to alignment padding after `type`. Add `__attribute__((packed))` and rerun — the offsets become 0, 1, 3, and the struct shrinks, at the cost of unaligned access for `length` and `checksum`.