18 points Forgret 1 day ago 10 comments

I've been frustrated by the lack of a truly portable, no-dependency printf for embedded and kernel development. Most solutions are either too bloated or missing key features. So I built Uprintf. It's a single-header library that gives you full printf (flags, width, precision, floats, even custom specifiers) from bare metal to desktop, with zero dependencies or #ifdef hell. Key features: · One header file, no dependencies, no dynamic allocation · Full standard support: %d, %x, %f, %.*s, etc. · Extensible with custom format handlers (add %T for your project) · Configurable: disable floats, set locale, etc. · MIT Licensed. GitHub: https://github.com/Ferki-git-creator/Uprintf I'd love your feedback and contributions!

fjfaase 1 day ago | parent

Nice work. I always have understood that snprintf does not write a null character when the produced string is longer than the given size. The snprintf function also can be called with a null pointer to calculate the length of the produced string.

You could add a c file with some unittests.

Forgret 1 day ago | parent

Thanks, I will make and add unit tests As you requested, I'm already starting to do it, but in the meantime, if you want, you can support the project with a star. :)

wahern 17 hours ago | parent

> I always have understood that snprintf does not write a null character when the produced string is longer than the given size.

snprintf always null-terminates when the buffer length is greater than 0 and there's no error. That is, if snprintf returns >= 0 and the buffer length is > 0, the output is null-terminated.

This should be clear from your local snprintf(3) man page (e.g. https://man.openbsd.org/snprintf), but also see the C23 standard (https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3220.pdf) and POSIX (https://pubs.opengroup.org/onlinepubs/9799919799/).

s_gourichon 16 hours ago | parent

Nice. Comprehensive unit tests are indeed welcome. Even a simple test code that tests all features, flags combinations, etc, and outputs a log. It will make easy for anyone to run it and compare the logs.

I had a bug:

    u_printf( my_output_cb, NULL, "%d" NL, -42 );
prints:

--42

I may have found an explanation. In u_parse_format(), case 'i': calls u_itoa( value, buffer, 10, false ); which outputs minus sign.

Then if ( number ) does if ( sign ) { output_cb( '-', ctx ); chars_written++; } which outputs another minus sign.

s_gourichon 16 hours ago | parent

Also floats seem to "forget" the integer part, and also have two minus signs when negative.

Forgret 7 hours ago | parent

Thanks, I will review your PR, and I have to thank you very much for saving my time and correcting the error.

cozzyd 12 hours ago | parent

Would be nice to know the code size e.g. on arm-none-eabi!

Forgret 7 hours ago | parent

Ok, I will make your request.

s_gourichon 7 hours ago | parent

Maybe the rabbit hole is much deeper than it seems.

Is it really possible to reconcile "no bloat" with "fully standard compliant"?

Maybe have a look at https://github.com/eyalroz/printf, if only for the test suite, which looks pretty comprehensive and still fails.

Maybe "key features" does not mean the same in all projects, making every project appear "unnecessarily bloated while missing key features" in every other context?