This project implements a custom version of the standard printf function in C, exploring two fundamentally different architectural approaches. Through this journey, I've mastered advanced C programming concepts including jump tables, bitmasks, modular design, and performance optimization.
The first implementation follows a straightforward approach using cascading if-else statements:
if (format == 'c')
handle_char();
else if (format == 's')
handle_string();
else if (format == 'd')
handle_integer();
// ... and so onCharacteristics:
- ✅ Simple and readable
- ✅ Easy to debug and understand
- ❌ Limited scalability
- ❌ Repetitive code patterns
- ❌ Linear time complexity O(n) for format lookup
The bonus implementation leverages sophisticated programming techniques:
Instead of linear if-else chains, I implemented function pointer arrays for O(1) lookup:
static void init_convert_table(t_lookup_tables *tables)
{
int i;
char *converters;
t_convert_func funcs[9];
converters = "%csdixXpu";
funcs[0] = ft_convert_percent;
funcs[1] = ft_convert_char;
funcs[2] = ft_convert_str;
funcs[3] = ft_convert_int;
funcs[4] = ft_convert_int;
funcs[5] = ft_convert_hex_lower;
funcs[6] = ft_convert_hex_upper;
funcs[7] = ft_convert_ptr;
funcs[8] = ft_convert_unsigned;
// Direct array mapping for instant access
}For the first time, I implemented bitmask operations to handle multiple formatting flags efficiently:
#define FLAG_MINUS 0x01 // -
#define FLAG_ZERO 0x02 // 0
#define FLAG_DOT 0x04 // .
#define FLAG_HASH 0x08 // #
#define FLAG_SPACE 0x10 // (space)
#define FLAG_PLUS 0x20 // +
// Check multiple flags simultaneously
if (flags & (FLAG_MINUS | FLAG_ZERO))
handle_alignment_conflict();Each flag has its dedicated handler through another jump table:
static void init_flag_table(t_lookup_tables *tables)
{
int i;
char *flags;
t_flag_handler funcs[8];
flags = "-0.# +*";
funcs[0] = handle_minus;
funcs[1] = handle_zero;
funcs[2] = handle_dot;
funcs[3] = handle_hash;
funcs[4] = handle_space;
funcs[5] = handle_plus;
funcs[6] = handle_star;
// Dynamic flag resolution
}static t_lookup_tables *get_tables(void)
{
static t_lookup_tables tables;
static int initialized = 0;
if (!initialized)
{
init_convert_table(&tables);
init_flag_table(&tables);
initialized = 1;
}
return (&tables);
}Benefits:
- 🎯 Single point of truth for all lookup tables
- 🚀 Lazy initialization (only when needed)
- 💾 Memory efficiency (initialized once)
The project is structured for maximum extensibility:
ft_printf/
├── src/
│ ├── converters/ # Format-specific handlers
│ ├── flags/ # Flag processing modules
│ ├── utils/ # Utility functions
│ └── tables/ # Jump table management
├── includes/
└── tests/
- Performance: O(1) vs O(n) lookup time
- Maintainability: Adding new formats requires minimal code changes
- Scalability: Easy to extend without touching existing code
- Memory Efficiency: Store multiple boolean flags in single integer
- Performance: Bitwise operations are faster than multiple comparisons
- Elegance: Complex flag combinations handled mathematically
- Singleton: Global state management
- Strategy: Different algorithms for different format types
- Factory: Dynamic function selection based on input
- Function pointers and arrays
- Static variables and initialization
- Modular compilation and linking
- Performance optimization techniques
# Mandatory version (simple if-chain)
make
# Bonus version (advanced architecture)
make bonus
# Clean build artifacts
make clean && make fcleanAfter compilation, the library can be used in projects:
# Link against the ft_printf library
cc main.c -L. -l:libftprintf.a -o main
# Run the interactive demo
./mainI developed a comprehensive testing suite that validates:
- All format specifiers (%c, %s, %d, %i, %u, %x, %X, %p, %%)
- Flag combinations (-, +, 0, #, space, *)
- Width and precision handling
- Edge cases and error conditions
- Performance benchmarks
| Feature | Mandatory | Bonus |
|---|---|---|
| Format Lookup | O(n) | O(1) |
| Flag Processing | Linear scan | Bitmask ops |
| Memory Usage | Lower | Optimized |
| Extensibility | Limited | High |
| Code Complexity | Simple | Advanced |
This project transformed my understanding of:
- System Programming: Low-level string manipulation and memory management
- Performance Optimization: Algorithmic improvements and efficient data structures
- Software Architecture: Modular design and separation of concerns
- C Mastery: Advanced language features and best practices
The bonus implementation demonstrates enterprise-level code organization, making it trivial to add new format specifiers or flags without disrupting existing functionality.
The modular architecture enables easy addition of:
- Color format specifiers (
%{red}s) - Custom numeric bases (
%bfor binary) - Advanced formatting options
- Multi-threading support
- Memory pool optimization
This project showcases the evolution from simple procedural code to sophisticated, scalable architecture - a journey every C programmer should experience.