Skip to main content
๐Ÿ“œ WAYPOINT LESSON

void* and the Cost of Erasure

โญโญโญ advancedโณ 15 min read๐Ÿ“ Lesson 175 of 225

Type-erased containers: what qsort teaches, byte-wise copies, alignment, and why the compiler cannot save you.

qsort is the master class

void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));

Four ingredients make it generic: a byte-addressed base, an element size (so the algorithm can move elements with memcpy), a count, and a comparison callback supplied by the caller. Every generic C API you will design mixes some subset of these.

What the cost is

Inside a void* container, elements are bytes: elem_at(base, i, size) is (char *)base + i * size. The compiler no longer knows element types โ€” wrong casts, wrong sizes, and wrong comparators are all silent until runtime. Genericity in C trades compile-time checking for flexibility; document and test accordingly.

Alignment still applies

A void* handed back to the caller must be as aligned as the data it represents. If your container allocates raw bytes, align them โ€” a double stored at an odd address is UB the moment it is loaded.

โšก Now practice

Ready to Code
Generic Mechanism DrillsByte-addressed genericity, compile-time dispatch, tagged unions, and X-macro tables โ€” mechanisms with observable contracts.
3 challenges ยท ยท ~24 min