ft_printf
ProjectM1
Reimplement printf with variadic arguments and the main conversions.
Requires
Unlocks
Guide
ft_printf is a milestone M1 project in C, done solo. You recreate a subset of the libc printf: a function that takes a format string and a variable number of arguments, prints the result on standard output and returns the number of characters written. It is packed as libftprintf.a and usually built on top of your libft. Behind the small surface it is a lesson in variadic functions and in writing a parser that is easy to extend.
What you will learn
- Variadic functions with
va_start,va_arg,va_copyandva_end, and the default argument promotions (charbecomesint) - Parsing a format string one character at a time and dispatching on the conversion
- Converting numbers to any base, signed and unsigned, without overflow
- Printing pointers as hexadecimal addresses
- Counting output precisely and propagating
writeerrors - Designing a small dispatch table so the bonus flags do not turn into one giant function
Before you start
- Previous nodes: Libft. You will reuse
ft_putchar_fd,ft_strlenand probablyft_itoa-style helpers. - Tools:
cc,make,ar,norminette,valgrind. - Read
man 3 printf(the "Conversion specifiers" and "Flag characters" sections) andman 3 stdarg. - The mandatory conversions are
%c,%s,%p,%d,%i,%u,%x,%Xand%%.
Plan of attack
- Day 1: write a skeleton that copies the format string to stdout and returns the count. Add the Makefile so
libftprintf.acontains your libft objects too (or merge libft sources into the build). - Day 1: add
%c,%sand%%. Decide what%sprints forNULLand match the realprintfon your system ((null)on glibc). - Day 2: write one generic
put_unsigned_base(value, base_digits)and use it for%u,%xand%X. - Day 2:
%dand%i, handlingINT_MINwithout negating it as anint(cast tolongfirst). - Day 3:
%p. Cast tounsigned long(oruintptr_t), prefix with0x, and check what your system prints for aNULLpointer ((nil)on Linux,0x0on macOS). - Day 3: compare your output and return value with the real
printffor every conversion, side by side, in a testmainkept outside the repository. - Day 4 (bonus): parse flags
-0.and field width, then# +and space. Store them in a small struct and pass the struct to each converter. - Day 5: norminette, valgrind, a tester, and a final read of the parser.
int ft_printf(const char *format, ...)
{
va_list args;
int count;
va_start(args, format);
count = print_format(format, &args);
va_end(args);
return (count);
}
Common pitfalls
- Using the real
printforsprintfinside the project: forbidden. - Return value off by one when a conversion prints nothing (empty string, precision zero in the bonus).
%xwith negative numbers: the argument is anunsigned int, read it as such.INT_MINandUINT_MAXedge cases.- Calling
va_argwithcharinstead ofint: undefined behaviour. - A Makefile that relinks, or a library that does not contain the libft objects it needs.
- Forgetting the
bonusrule while claiming the bonus. - Behaviour with a trailing lone
%is undefined; do not crash on it.
How it is evaluated
- Peer evaluation then Moulinette. The evaluator checks the Makefile (no relink,
libftprintf.aproduced), norminette and the absence of forbidden functions. - Each conversion is tested against the real
printf: same output and same return value, includingNULLstrings,NULLpointers,0,INT_MIN,INT_MAXandUINT_MAX. - Leaks are checked on a test
main. - The bonus is graded only if the mandatory part is perfect. Flags are tested in combination (
%-10.5d,%#x,% d,%+d). - You must explain how
va_argworks and why your design is extensible.