GithubHelp home page GithubHelp logo

casuallywill / nanoprintf Goto Github PK

View Code? Open in Web Editor NEW

This project forked from charlesnicholson/nanoprintf

0.0 1.0 0.0 109 KB

A tiny embeddable printf replacement written in C89/C99.

License: The Unlicense

Python 1.95% CMake 8.36% Shell 2.91% C 38.69% C++ 48.10%

nanoprintf's Introduction

nanoprintf

CircleCI

nanoprintf is an implementation of snprintf and vsnprintf for embedded systems that aims for C11 standard compliance.

nanoprintf makes no memory allocations, uses less than 100 bytes of stack, and is smaller than 5KB of ARM Cortex-M object code when optimized with all the bells and whistles turned on (slightly larger on x64, where you don't want to use it anyway).

nanoprintf is a single header file in the style of the stb libraries. The rest of the repository is tests and scaffolding and not required for use.

nanoprintf is written in C89 for maximal compiler compatibility. C99 or C++11 compilers are required (for uint64_t and other types) if floating point conversion or large modifiers are enabled. nanoprintf does include standard headers but only uses them for types and argument lists; no calls are made into stdlib / libc, with the exception of any internal double-to-float conversion ABI calls your compiler might emit.

nanoprintf is statically configurable so users can find a balance between size, compiler requirements, and feature set. Floating point conversion, "large" length modifiers, and size write-back are all configurable and are only compiled if explicitly requested, see Configuration for details.

Motivation

tinyprintf doesn't print floating point values.

printf defines the actual standard library printf symbol, which isn't always what you want. It stores the final converted string (with padding and precision) in a temporary buffer, which makes supporting longer strings more costly. It also doesn't support the %n "write-back" specifier.

No other embedded-friendly printf projects that I could fine are in the public domain and have single-file implementations. Really though, I've just wanted to try my hand at a really small printf system for a while now.

Usage

  1. Copy nanoprintf.h into your codebase somewhere.

  2. Add the following code to one of your .c or .cpp files to compile the nanoprintf implementation:

    #define NANOPRINTF_IMPLEMENTATION
    #include "path/to/nanoprintf.h"
    
  3. To call, just #include "path/to/nanoprintf.h" as usual and call the functions.

  4. Compile your code with your nanoprintf configuration flags. Alternately, wrap nanoprintf.h in your own header that defines all of your configuration flags, and use that everywhere in steps 2-3.

API

nanoprintf has 4 main functions:

  • npf_snprintf: Use like snprintf.
  • npf_vsnprintf: Use like vsnprintf (va_list support).
  • npf_pprintf: Use like printf with a per-character write callback (semihosting, UART, etc).
  • npf_vpprintf: Use like npf_pprintf but takes a va_list.

The pprintf variations take a callback that receives the character to print and a user-provided context pointer.

Pass NULL or nullptr to npf_[v]snprintf to write nothing, and only return the length of the formatted string.

nanoprintf does not provide printf or putchar itself; those are seen as system-level services and nanoprintf is a utility library. nanoprintf is hopefully a good building block for rolling your own printf, though.

Configuration

nanoprintf has the following static configuration flags. You can either inject them into your compiler (usually -D flags) or wrap nanoprintf.h in your own header that sets them up, and then #include your header instead of nanoprintf.h in your application.

  • NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS: Set to 0 or 1. Enables floating-point specifiers.
  • NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS: Set to 0 or 1. Enables oversized modifiers.
  • NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS: Set to 0 or 1. Enables %n for write-back.
  • NANOPRINTF_VISIBILITY_STATIC: Optional define. Marks prototypes as static to sandbox nanoprintf.

If a disabled format specifier feature is used, no conversion will occur and the format specifier string simply will be printed instead.

Formatting

Like printf, nanoprintf expects a conversion specification string of the following form:

[flags][field width][.precision][length modifier][conversion specifier]

  • Flags

    None or more of the following:

    • 0: Pad the field with leading zero characters.
    • -: Left-justify the conversion result in the field.
    • +: Signed conversions always begin with + or - characters.
    • : (space) A space character is inserted if the first converted character is not a sign.
    • #: Writes extra characters (0x for hex, . for empty floats, '0' for empty octals, etc).
  • Field width

    A number that specifies the total field width for the conversion, adds padding. If field width is *, the field width is read from the next vararg.

  • Precision

    Prefixed with a ., a number that specifies the precision of the number or string. If precision is *, the precision is read from the next vararg.

  • Length modifier

    None or more of the following:

    • h: Use short for integral and write-back vararg width.
    • L: Use long double for float vararg width (note: it will then be casted down to float)
    • l: Use long, double, or wide vararg width.
    • hh: Use char for integral and write-back vararg width.
    • ll: (large specifier) Use long long for integral and write-back vararg width.
    • j: (large specifier) Use the [u]intmax_t types for integral and write-back vararg width.
    • z: (large specifier) Use the size_t types for integral and write-back vararg width.
    • t: (large specifier) Use the ptrdiff_t types for integral and write-back vararg width.
  • Conversion specifier

    Exactly one of the following:

    • %%: Percent-sign literal
    • %c: Characters
    • %s: Null-terminated strings
    • %i/%d: Signed integers
    • %u: Unsigned integers
    • %o: Unsigned octal integers
    • %x / %X: Unsigned hexadecimal integers
    • %p: Pointers
    • %n: Write the number of bytes written to the pointer vararg
    • %f/%F: Floating-point values

Floating Point

Floating point conversion is performed by extracting the value into 64:64 fixed-point with an extra field that specifies the number of leading zero fractional digits before the first nonzero digit. No rounding is currently performed; values are simply truncated at the specified precision. This is done for simplicity, speed, and code footprint.

Despite nano in the name, there's no way to do away with double entirely, since the C language standard says that floats are promoted to double any time they're passed into variadic argument lists. nanoprintf casts all doubles back down to floats before doing any conversions.

Development

To get the environment and run tests (linux / mac only for now):

  1. Clone or fork this repository.
  2. Run ./b from the root.

This will build all of the unit, conformance, and compilation tests for your host environment. Any test failures will return a non-zero exit code.

The nanoprintf development environment uses cmake and ninja. If you have these in your path, ./b will use them. If not, ./b will download and deploy them into path/to/your/nanoprintf/external.

nanoprintf uses CircleCI for continuous integration builds. The CircleCI builds use this Docker image on Docker Hub. The Dockerfile for the CircleCI builds lives here.

Limitations

No wide-character support exists: the %lc and %ls fields require that the arg be converted to a char array as if by a call to wcrtomb. When locale and character set conversions get involved, it's hard to keep the name "nano". Accordingly, %lc and %ls behave like %c and %s, respectively.

Currently the only supported float conversions are the decimal forms: %f and %F. All other float conversions (exponent form, hexadecimal exponent form, dynamic precision form) behave like %f and %F. Pull requests welcome!

Acknowledgments

Float-to-int conversion is done using Wojciech Muła's float -> 64:64 fixed algorithm.

nanoprintf's People

Contributors

charlesnicholson avatar ddz avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.