This project has been created as part of the 42 curriculum by jiylee.
- Helping me understand how printf() works by implementing it myself, and learn about using a variable number of arguments, variadic functions in C.
- This project involves recoding printf() for my programs in the future as assignments by 42school. Its version is 12.1 without the Bonus part.
- printf(), variadic functions in C
git clone <repository-url> working_directory
cd working_directory-
- Type
makein the commandline of where this Makefile exists, then you'll get "*.o" files and "libftprintf.a" - Type
make cleanto remove just "*.o" files. - Type
make fcleanwhich means fully-clean, to remove not only "*.o" files, but also "libftprintf.a". - Type
make reto fully-clean then get "*.o" files and "libftprintf.a" again. - After you get "libftprintf.a", type
cc -Wall -Wextra -Werror main.c libftprintf.a -o programto compile together. - Type
./programto execute.
- Type
#include "ft_printf.h"
int main(void)
{
ft_printf("Hello %s, you are %d years old!\n", "World", 42);
ft_printf("Hex: %x, Pointer: %p\n", 255, &main);
return (0);
}Compile with:
cc -Wall -Wextra -Werror main.c libftprintf.a -o programExecute the program with:
./program| Specifier | Description |
|---|---|
| %c | Single character |
| %s | String |
| %p | Pointer address in hexadecimal |
| %d | Signed decimal integer |
| %i | Signed integer |
| %u | Unsigned decimal integer |
| %x | Unsigned hexadecimal (lowercase) |
| %X | Unsigned hexadecimal (uppercase) |
| %% | Percent sign |
ft_printfscans the format string looking for%- All characters before
%are identified as a contiguous segment within the original format string and written in a singlewrite()call - When
%is found, the next character is read andft_handle_formatis called ft_handle_formatdispatches to the appropriate print function based on the specifier- This continues until the end of the format string
Why Batch Write Approach?
- Instead of calling
write()one character at a time, consecutive plain-text characters up to the next%are written together in a singlewrite()call - No separate memory buffer is allocated; the pointer to the original format string is used directly
- Minimizes the number of
write()system calls, reducing system call overhead
For %d, %u, %x, %X, %p, I use recursion to print digits in correct order:
- If
n >= base, recursively call withn / basefirst - Then print
n % baseas the current digit - This ensures the most significant digit prints first
Why recursion?
- Simple and elegant solution
- Avoids needing a buffer to reverse digits
- Stack naturally handles digit ordering
ft_printf/
├── ft_printf.c ← ft_printf, ft_handle_format
├── ft_print_string.c ← ft_print_char, ft_print_str
├── ft_print_hex.c ← ft_print_hex, ft_print_hex_upper, ft_print_ptr
├── ft_print_nbr.c ← ft_print_nbr
├── ft_printf.h ← All function prototypes
└── Makefile
| File | Responsibility |
|---|---|
| ft_printf.c | Main logic and format dispatching |
| ft_print_string.c | Character and string output |
| ft_print_hex.c | Hexadecimal and pointer output |
| ft_print_dec.c | Decimal number output (signed/unsigned) |
Why this separation?
- Each file handles related functionality
- Stays within Norm's 5 functions per file limit
- Easy to maintain and extend
-
-
- I used only Opus 4.5 of Claude.
-
- Getting hints of how logics should flow when I got stuck.
- Getting detailed knowledge of everything like knowing full-name of each title.
- Getting evaluation of my original source-code and refactored one, to choose which one should survive.
- Getting to know why this code must be like this, like each intention of some codes, which cases I should use which code, as the right code in the right place.
-