Methods

42 (III): ft_printf, our own printf

Recreating printf with variadic arguments: formatters, widths, and the illusion

2 min read

When you wrote your first program, someone told you that printf is used to display things on screen. Nobody explains how the formatting magic works: how it knows that %d is an integer and %s is a string. ft_printf is the project where this stops being magic: you have to rewrite printf yourself.

The problem

printf is a variadic function (it accepts as many arguments as you want, and C doesn't tell you how many or of what type they are). The only information is the format string, which you have to traverse character by character: when you find a %, the next character tells you what to print. My scope was the classic set: %c for characters, %s for strings, %d and %i for integers, %u, %x and %X for unsigned and hexadecimal, %p for pointers, and the %% literal. And a detail the documentation skips: the function must return the total number of characters printed, not just display them.

How I approached it

I separated the string traversal from the printing of each type. A loop that detects the % and a helper function for each specifier: character, string, integer, hexadecimal, pointer. Each helper prints and counts, and at the end the total is summed up. The cases that bled the most were the ones nobody tests: a NULL string that should be displayed as (null), the minimum value of a signed integer, which cannot be safely reversed, and null pointers. To test it, the most useful technique was comparing the output byte by byte with the real printf: if the character count doesn't match, something is wrong. The repository, 42_ft_printf, was organized in a few pieces: the main function, two utility layers, and a header.

What I took away

The big lesson is about stdarg.h, the piece with which C passes variable-length arguments through the stack: when there are no types, everything depends on the format string and the passed arguments matching, and the compiler won't warn you if they don't. I also learned that everyday functions hide a lot of engineering: printf carries decades of optimizations and extensions, and even though my version only covers a part, now, when I write it, I know exactly what happens underneath. And a practical thing: ft_printf has since been the printing function for all my 42 projects, companion to get_next_line for reading files line by line. The next step in the series was the first exam, rank 2. The toolbox grows.