<span>printf</span> is actually an ultra-small, ultra-fast, zero-dependency formatted output library specifically designed for embedded systems. The standard libc <span>printf</span> often bloats the code size by over 20 KB on MCUs and may not be thread-safe. This library consolidates all necessary code into <span>printf.c</span>, achieving everything in one file, and can trim features like floating-point and exponential as needed.
What pain points does it solve?
| Pain Point | Traditional libc <span>printf</span> |
This tiny printf |
| Code Size | Often > 20 KB | Only ~600 lines of source code, a few KB |
| Dependencies | Requires a complete C standard library | Zero dependencies, single file |
| Thread Safety | May have race conditions | Fully reentrant, thread-safe |
| Customizability | Fixed functionality, cannot remove | Can disable floating-point, exponential, etc. via macro switches |
| Portability Difficulty | Requires linking with libc, many platform restrictions | Only needs an implementation of <span>_putchar</span> |
| Debugging/Testing | Hard to ensure all formats are correct | Over 400 unit tests, high coverage |
In summary: If you want to save memory, speed, and stability, choose this.
How easy is it to set up?
- 1. Add
<span>printf.c</span>and<span>printf.h</span>to your project. - 2. Implement a low-level character output function
<span>_putchar</span>(e.g., sending bytes via UART).void _putchar(char ch) { // Send ch to serial port, screen, or debug output UART_SendByte(ch); } - 3. Call it just like you would with the standard library:
printf("Temperature is %0.2f°C\n", temperature); sprintf(buf, "ID=%08X", device_id); - 4. Want more flexibility? Use
<span>fctprintf</span>to treat any callback as a stream:fctprintf(my_log_func, NULL, "Error code: 0x%X\n", err);
If you’re concerned about buffer overflow, it is highly recommended to use <span>snprintf</span>, specifying the maximum buffer length for safety and peace of mind.
Advantages & Disadvantages
Advantages
- • Small Size: Around 600 lines of source code, runs in a few KB.
- • Zero Dependencies: No external libraries required, directly compiled into the MCU.
- • Full Features: Supports
<span>%d %u %x %f %e %g %s %c %p</span>, along with complete formatting options like width, precision, and flags. - • Customizable: Macro switches to disable unnecessary features, further reducing size.
- • Thread Safe: Does not use global static buffers, allowing concurrent calls.
- • Test Coverage: Over 400 test cases, ensuring basic standard compliance.
Disadvantages
- • No Wide Character (wchar_t) Support: Direct printing of wide characters for Chinese requires conversion.
- • Floating Point Support Slightly Increases Code Size: If the MCU lacks hardware floating point, disabling macros will save space.
- • Requires Implementation of
<span>_putchar*</span>Output: This may pose a slight barrier for beginners (but most platforms already have UART examples).
ConclusionEmbedded projects often struggle with firmware size due to <span>printf</span><span>, and this tiny printf offers a solution with </span><strong><span>“one line of code + one callback”</span></strong><span>, retaining powerful formatting capabilities while minimizing size. Customizable, zero-dependency, and thread-safe, it meets the stringent requirements for </span><strong><span>code size</span></strong><span>, </span><strong><span>performance</span></strong><span>, and </span><strong><span>reliability</span></strong><span>. If you're struggling with logging, debugging, or UI text on your MCU, give it a try!</span>
Project Address: https://github.com/mpaland/printf