C Library & Correctnessfoundational
Have you ever implemented from scratch any functions from the C Standard Library (that ships with most compilers)? Created your own because functions in C library didn't support something you needed?
0 upvotes
Practice with AISoon
Reimplementing standard-library functions is common in embedded work. The usual technical motivations are:
- Code size / footprint. The library version pulls in too much. The canonical example is
printf: full implementations drag in float formatting, wide-char support, and locale code (kilobytes of flash). A "printf-lite" that supports only%d/%u/%x/%c/%scan be a fraction of the size. Similarly, custommemcpy/memset/strcpyavoid library bloat on tiny MCUs. - Missing in a freestanding / minimal runtime. In a freestanding environment (no OS, bare metal) only a small part of the standard library is guaranteed. Reduced libraries like newlib-nano or picolibc omit or stub functions, and some toolchains require you to provide your own. Heap functions in particular may be absent or require porting (
_sbrk). - Performance. A hand-tuned
memcpy/memsetthat uses word- or burst-sized transfers, DMA, or architecture-specific instructions can far outperform a generic byte-loop on the target. - Determinism / real-time. Replacing
malloc/freewith a fixed-block pool allocator (same API, deterministic timing) so real-time code never hits the variable-latency system heap. - Custom behavior / retargeting. Implementing the low-level hooks (
_write,_read,_sbrk,fputc) soprintf/scanftalk to a UART or RTT instead of a nonexistent console; or amemcpyvariant that is safe across volatile/MMIO regions.
Common functions reimplemented in practice: memcpy, memset, memmove, strlen/strcpy/strcmp, malloc/free, and a trimmed printf/snprintf. A simple example of a size-optimized memset:
c
void *my_memset(void *dst, int c, size_t n) {unsigned char *p = dst;while (n--) *p++ = (unsigned char)c;return dst;}
(A production version would copy word-at-a-time once aligned, handling the head/tail bytes separately, for speed.) The key engineering caution is to keep the same contract as the standard function (return values, overlap semantics, NUL handling) so callers behave identically.
