This project has been created as part of the 42 curriculum by damorim-.
ft_printf is a 42 School project that consists of recoding a simplified,
personal version of the standard C library function printf(). The goal is
to deeply understand how variadic functions work in C — how a function can
accept a variable, unknown-at-compile-time number of arguments — and how a
format string is parsed character by character to decide what to do with
each argument.
The project is delivered as a static library, libftprintf.a, exposing a
single public function:
int ft_printf(const char *format, ...);ft_printf reproduces the behaviour of the original printf for the
following conversions:
| Conversion | Meaning |
|---|---|
%c |
Character |
%s |
String |
%p |
Pointer address (hexadecimal) |
%d / %i |
Signed decimal integer |
%u |
Unsigned decimal integer |
%x |
Unsigned hexadecimal (lowercase) |
%X |
Unsigned hexadecimal (uppercase) |
%% |
A literal % character |
Just like the original, the function returns the total number of characters
written to standard output, or -1 if the format string is NULL.
This version relies on libft, the personal C library built in
an earlier 42 project, for helpers such as ft_strlen, ft_itoa, and
ft_calloc.
The project is built with the provided Makefile, which compiles every
source file, builds libft as a dependency, and archives everything into
a single static library.
make # builds libftprintf.a (compiles libft first)
make clean # removes object files (project + libft)
make fclean # removes object files AND the compiled library
make re # fclean + allTo use ft_printf in your own project:
- Copy the project folder (including the
libftsubfolder) into your project, or add it as a submodule. - Compile the library with
make. - Include the header and link against the archive:
#include "ft_printf.h"
int main(void)
{
int len;
len = ft_printf("Hello, %s! You are %d years old (0x%x in hex).\n",
"42", 21, 21);
ft_printf("Characters written: %d\n", len);
return (0);
}cc -Wall -Wextra -Werror main.c -L. -lftprintf -o my_program
./my_programThere is no bundled test suite in this repository. Manual testing was done
by comparing ft_printf's output and return value against the system
printf for each conversion, including edge cases such as NULL strings
and pointers, 0, negative numbers, and %%.
No complex data structure is needed for this project; the core challenge is parsing and control flow, not data organisation. The design choices are:
-
Single left-to-right scan of the format string.
ft_printfwalks the format string once, index by index. Every regular character is written directly withwrite; every%triggers a lookup atcheck_format, which reads the character right after the%to decide which conversion handler to call. This gives O(n) time complexity in the length of the format string (plus the cost of writing the arguments themselves), and needs no extra memory to hold the format string itself. -
va_listfor variadic arguments. Since the number and types of arguments are only known at the call site, the C standard<stdarg.h>mechanism (va_start,va_arg,va_end) is used to walk the argument list in the same order as the conversions appear in the format string. This mirrors exactly how the realprintfis implemented. -
One static function per conversion. Each conversion (
%c,%s,%p,%d/%i,%u,%x,%X,%%) is isolated in its own function and its own file, following the 42 norm (one function's worth of logic per file, no more than ~25 lines per function). This keepscheck_formata simple dispatcher and makes each conversion independently testable and readable. -
Recursion for base conversion. Printing an integer in a base other than 10 (
%x,%X, and the hex digits of%p) is done recursively: the function calls itself onn / 16before writing the current digitn % 16. This naturally prints digits most-significant-first without needing to build and reverse a string first, at the cost of using the call stack instead of heap memory. -
ft_itoafor base-10 conversion.%d/%ireuseft_itoafromlibft, which already handles the sign and theINT_MINedge case correctly, avoiding duplicated, error-prone integer-to-string logic.%uuses a dedicated unsigned counterpart (ft_unsigned_itoa) since unsigned integers cannot go through the signedft_itoawithout risking overflow on values aboveINT_MAX. -
Defensive
NULLhandling.%son aNULLpointer prints(null)and%pon aNULLpointer prints(nil), matching glibc'sprintfbehaviour, so the library doesn't crash on the same inputs a real program might pass it.
Classic references used while working on the topic:
printf(3)— Linux man page — reference for conversion specifiers and return value semantics.- C Standard, §7.21.6.1
fprintf— cppreference page detailing the formal behaviourprintf-family functions must follow. stdarg.h— cppreference — documentation onva_list,va_start,va_arg,va_endand how variadic functions work in C.- GeeksforGeeks.
- Youtube.
An AI assistant (Claude) was used strictly as a documentation and review aid, not to write or debug the C implementation itself:
- Drafting and structuring this
README.md(Description, Instructions, Technical Choices, and Resources sections) from the existing source code and Makefile. - Explaining, in the "Technical Choices" section above, the reasoning
behind design decisions (single-pass parsing, recursion for base
conversion,
va_listusage) that were already implemented in the code, so they could be documented clearly and accurately.
All ft_printf logic — the format-string parser, the variadic argument
handling, and every conversion function — was designed, written, and
debugged manually, in line with the 42 evaluation requirement that the
code itself reflects the student's own understanding.