In embedded system development, the <span>printf</span> function is a commonly used tool for debugging and information output. However, the standard library’s <span>printf</span> implementation is often large and consumes valuable resources, especially on resource-constrained microcontrollers. To address this issue, <span>nanoprintf</span> has emerged! It is a lightweight and powerful implementation of <span>snprintf</span> and <span>vsnprintf</span>, specifically designed for embedded systems.
Extremely Lightweight, Outstanding Performance
<span>nanoprintf</span> aims for minimalism. Its code is entirely written in C99 and has been meticulously optimized, with the compiled code size on the Cortex-M0 architecture being only 740-2640 bytes (depending on configuration), and it occupies very little memory, with stack space under 100 bytes. This makes it highly suitable for resource-constrained embedded environments, such as Bootloaders. You need not worry about it consuming a lot of flash space or running slowly; it provides a solution that minimizes code size while ensuring functionality.

Rich Features, Flexible Configuration
Despite being lightweight, <span>nanoprintf</span> boasts a wealth of features. It supports various formatting specifications, including:
- Basic data types: characters, strings, signed/unsigned integers.
- Floating-point numbers: decimal representation (
<span>%f</span>). (Although formats like<span>%e</span>,<span>%g</span>, and<span>%a</span>for scientific notation are not yet implemented, contributions are welcome!) - Field width and precision control: precise control over output format.
- Length modifiers: supports
<span>h</span>,<span>l</span>,<span>ll</span>,<span>j</span>,<span>z</span>, and<span>t</span>modifiers for handling integers of different sizes. - Binary output: optional configuration, supports
<span>%b</span>for formatting binary numbers. - Write count: optional configuration, supports
<span>%n</span>to write the number of characters written to a specified pointer.
Additionally, <span>nanoprintf</span> supports custom output functions, allowing developers to direct output to various peripherals such as UART, SPI, etc. By configuring macros, you can choose to enable or disable different features based on actual needs, achieving the best balance between code size and functionality.

Safe and Reliable, Easy to Use
<span>nanoprintf</span> also considers safety. The <span>npf_snprintf</span> and <span>npf_vsnprintf</span> functions adhere to the C standard, preventing buffer overflows. You can enable stricter safety checks by defining the macro <span>NANOPRINTF_SNPRINTF_SAFE_EMPTY_STRING_ON_OVERFLOW</span>, which returns an empty string on buffer overflow, effectively preventing potential security risks.
<span>nanoprintf</span> is easy to use; simply include the header file and call the corresponding functions. It provides four main functions:
<span>npf_snprintf</span>: similar to the standard library’s<span>snprintf</span>function.<span>npf_vsnprintf</span>: similar to the standard library’s<span>vsnprintf</span>function, supporting variable-length argument lists.<span>npf_pprintf</span>: similar to<span>printf</span>, but uses a custom character output callback function.<span>npf_vpprintf</span>: similar to<span>npf_pprintf</span>, but supports variable-length argument lists.
<span>nanoprintf</span> functions return the number of characters written (or to be written) (excluding the null terminator).
Design Philosophy and Advantages
<span>nanoprintf</span> is designed with a focus on extreme lightweight. To reduce code size, most features are concentrated in the <span>npf_vpprintf</span> function, which sacrifices some code readability and modularity, but for embedded systems, code size is often more critical than code readability. Of course, contributions to improve code structure while maintaining code size are welcome.
Comparison with Other printf Implementations
Compared to other embedded printf implementations, nanoprintf has the following advantages:
- Smaller: nanoprintf is significantly smaller than other implementations in minimal configuration.
- More Flexible: nanoprintf can customize features through configuration macros, balancing size and functionality.
- Safer: nanoprintf provides safety options to prevent buffer overflows.
- Easier to Use: nanoprintf is simple to use and easy to integrate into projects.
Conclusion
<span>nanoprintf</span> is a powerful, safe, reliable, and highly configurable ultra-lightweight <span>printf</span> implementation, making it ideal for embedded system development. Its extremely small code size and excellent performance make it a perfect choice for resource-constrained environments. If you need a lightweight and efficient <span>printf</span> implementation, consider trying <span>nanoprintf</span>!
Project address: https://github.com/charlesnicholson/nanoprintf