# printf() implementation comparison

This page is a rough comparison between various printf() implementaions. Not all printf() implementations are equal, while almost all will do the 'd', 'ld', 'u', 'lu', and 's' convertions ... even just adding a precision to one of the int formatters might not do the right thing.

Note that if you want a portable version of printf() in your code, you are much better off using something that natively parses the format string. This ensures that you get the same parsing behaviour on all platforms. Otherwise you are just waiting for your code to be run on some weird platform, and crash or possibly have a security problem. Note that this page gives information about what you should look for in a string library printf implementation, and the problems with just using the host implementation sprintf()/snprintf() calls.

For a comparison of string libraries, some of which include a portable printf() like function, you should look at this page

If you want to learn how printf() implementations are written, you can look at this simple printf code. However if you want to use one I'd recommend one of the better ones from the below list as they have more features and comply to the standards better.

- ## GNU libc 2.3.x

  Allocation policy:
    Automatic
  Format parsing:
    Native
  Double printing:
    Native
  Problems:
    None
  User extensions:
    Can register single letter customer format specifiers, can't be done in warning compatible way for static format checkers.
  Version:
    2.3.2

  Looks like a conformaing implementation, I reported a couple of corner case bugs that were fixed for 2.3.x. However there is an "issue" where if you pass an invalid multibyte string to the printf like functions then it fails only if you give it a precision.

  There is a 'I' flag extension, which is pretty much zero availability elsewhere. There are also the std. extentions of 'S' and 'C'. User formatters are possible, but static format checkers can't cope, and they are limited to single characters.

- ## FreeBSD-5.0

  Allocation policy:
    Automatic
  Format parsing:
    Native
  Double printing:
    Native
  Problems:
    None
  User extensions:
    No
  Version:
    FreeBSD-5.0-RELEASE

  Looks like a conformaing implementation.

  There are quite a few "extentions" like 'D', 'O', 'U' and 'qd' ... which have limited availability elsewhere, however they are deprecated. There are also the std. extentions of 'S' and 'C'. No way to have user defined formatters.

- ## uClibc

  Allocation policy:
    Automatic
  Format parsing:
    Native
  Double printing:
    Native
  Problems:
    Fails for thousands seperator support for non base 10 integer printing (this is std. compliant).
  User extensions:
    Can register single letter customer format specifiers, can't be done in warning compatible way for static format checkers. Has problems with zero argument custom formatters. Also has a hard limit on the number of custom formatters.
  Version:
    cvs (2003-09-24)

  This looks like a conforming implementation.

  Supports a bunch of common extentions, like 'm', 'q', 'I'. Has register_printf_function() which is an API copy from GNU libc, and works the same way .. however it has a hard limit on the number of formatters you can add. Currently has a bug where using a i18n positional precision/width will error out of the printf function, if the custom format is defined to not take any arguments.

- ## klibc

  Allocation policy:
    Limited
  Format parsing:
    Native
  Double printing:
    N/A
  Problems:
    No double support, of any kind. Thousands seperator support only does a specific "kernel" locale. No i18n support. Doesn't support corner cases with regard to precision etc.
  User extensions:
    No
  Version:
    0.77

  A simple printf() like function. It's not very stds. compliant, but the code itself is quite nice (mainly because it doesn't try to follow the stds. in many cases) ... if you just need the different types of int outputing, C style strings and don't care about complete stds. compliance this is a good place to start. Note however that I'm somewhat biased, as a very old version of this is what the Vstr printf() like function evolved from.

- ## dietlibc

  Allocation policy:
    Automatic (implemented via. two calls to snprintf)
  Format parsing:
    Native
  Double printing:
    N/A
  Problems:
    No i18n support. No thousands seperator support. Only implements 'f' and 'g' (which maps directly to 'f') for double support. 't' 'j' and 'z' prefixes aren't supported for int types. Precision support is almost completely broken.
  User extensions:
    No
  Version:
    0.22

  A simple printf() like function. It's not very stds. compliant, and the code itself is a terrible #ifdef and goto hell which looks much worse than many full implementations. As well as non support for some asspects of the std. 'g' is implemented and broken, precision support is just brainddead and it actually has an option to disable NULL checking in printf (a single if statement -- which stops your programs from crashing) but yet always leaves in and extension which does integer output in base 2.

- ## Vstr string library

  Allocation policy:
    Automatic
  Format parsing:
    Native
  Double printing:
    Native, host or zero (depending on build time options)
  Problems:
    None
  User extensions:
    Yes
  Version:
    1.0.13

  A conformaing implementation.

  There are ways to specify custom formatters, and do it in such a way that static checkers of format strings won't be confused. For a lot more information, see other pages on this site. Note that I wrote this, so I'm possibly biased.

- ## Trio I/O library

  Allocation policy:
    Automatic
  Format parsing:
    Native
  Double printing:
    Native
  Problems:
    Has a hard limit on the number of formats per call.
  User extensions:
    Yes, but can't be done in warning compatible way for static format checkers.
  Version:
    1.10 (April 2003)

  The printf() like function appears to be stds. compliant, note that the previous versions had a number of issues and as other projects just copy the C files into their build you should check which version of trio they used. Of particular note, glib-2.2.1 and libxml2-2.4.24 both have buggy versions. Also worth noting is that the i18n format parameter modifiers have an arbitrary limit, and the double output is custom code that may well not produce the same output as a real implementation and as an I/O library the output model isn't very good for a dynamically expanding string.

  User defined formaters are supported, however they are done in such a way that the gcc warning parser (and any other static, non programable, format checker) makes them useless.

- ## GLib

  Allocation policy:
    Automatic
  Format parsing:
    Native checker, and trio (passes directly to host if build time checker passes)
  Double printing:
    Host or Native (via. trio)
  Problems:
    Has a hard limit on the number of formats per call (in trio mode). Relies on host implementation not changing from build time (in host mode). Printing NIL chacters silently fails.
  User extensions:
    No
  Version:
    2.2.1

  The printf implementation calls the host implementation of sprintf/asprintf/etc. if it looks like a valid C99 implementation, and uses the trio library internally otherwise (this is only true as of version 2.2.0 though -- before that it'll just crash in some instances). So it's impossible to have custom formatters (the most obvious annoying fallout of this is that you can't add a GString to a GString as part of a printf() call) and portability is a problem (Although it is supposed to be valid to work with data that has NIL bytes in it doing so loses data in certain cases -- I've submitted a patch for the last problem).

## FreeBSD-4.7

Allocation policy:
  Automatic
Format parsing:
  Native
Double printing:
  Native
Problems:
  Unimplemented most newer formats
User extensions:
  No
Version:
  FreeBSD-4.7-RELEASE

Doesn't understand 'A', 'a', 'F', 'hhd', 'td', 'zd', 'ls', 'lc' or thousands seperators.

There are quite a few "extentions" like 'D', 'O', 'U' and 'qd' ... which have limited availability elsewhere. No way to have user defined formatters.

- ## Mark Martinec snprintf (include asprintf())

  Allocation policy:
    Automatic
  Format parsing:
    Native
  Double printing:
    N/A
  Problems:
    Unimplemented most newer formats, no double support at all. No i18n support.
  User extensions:
    No

  Not a bad implementation for what is actually done (it seems to be fairly stds. compliant, and has optional platform specific behaviour, it seems to have been written by reading man pages from what I can see -- no small feat), however there is a lot of missing functionality (most of which it readily admits to on the web page). Probably the most noticable are the missing 'F', 'f', 'E', 'e', 'zu', 'zd', 'ju', 'jd', 'td', 'hhd', 'n' etc. formats. Next being missng i18n format modifiers, and the 'n' format.

  No way to have user defined formatters.

- ## Samba's Patrick Powell snprintf() variant

  Allocation policy:
    Automatic
  Format parsing:
    Native (passes directly to host if build time checker passes)
  Double printing:
    Native
  Problems:
    Unimplemented most newer formats. No i18n support. Bad precision handling on double formatting. Bad empty precision handling. Relies on host implementation not changing from build time (in host mode).
  User extensions:
    No
  Version:
    2.2.7, of samba

  This code was originally posted to BrugTraq, and has since been hacked on by at least four more people. This is the version in Samba, however there are other versions of this code floating around as it was a favourite for people to just copy and paste into their project. Note that the version of patrick powell's code in in samba is improved upon the original.

  This is very poor for stds. compliance, it doesn't even support '#x' to print a leading "0x" before the number. '\'' (thousand modifiers), 'A', 'a', 'F', 'zd', 'td', 'hhd', etc. and i18n format parameter modifiers are all completly missing. An empty precision format doesn't make the precision zero. Unspecified precisions are wrong on double values, and zero specified ones aren't correct for octal etc.

- ## Apache HTTPD snprintf()

  Allocation policy:
    Specified limit
  Format parsing:
    Native
  Double printing:
    Native
  Problems:
    Unimplemented most newer formats. No i18n support. Buffer overflows. Unspecified precision is broken. Corner cases for "special" flag are broken.
  User extensions:
    No
  Version:
    2.0.40, of apache-httpd

  '\'' (thousand modifiers), 'a', 'F', 'Lf', 'lld', 'td', 'zd', 'hhd' , etc. and i18n format parameter modifiers are all completly missing (although 'qd' is available for "long long" ints). 'A' isn't the std. formatter but a custom one. Unspecified precision is broken, as is corner cases for octal etc. also infinity/nan output is not correct with regard to case. Buffer overflows are possible in the integer formatting paths

  Apart from the static extensions 'A' and 'I', this is the basis of the OSSP str library implementation.

- ## Sfio fprintf

  Allocation policy:
    Does output flushes at limits (so atomic operations aren't possible)
  Format parsing:
    Native
  Double printing:
    Native
  Problems:
    Unimplemented most newer formats, incomplete double support. No i18n support. Bad case handling for uppercase double infinity
  User extensions:
    No
  Version:
    sfio97, of sfio

  The sfio97 version available here is the version I looked at, it's possible that the 2002 versions fixes some of the problems. However I didn't get access to it.

  This is fairly stds. compliant, for when it was written. However it doesn't support '\'' (thousand seperators) 'td', 'jd', 'zd', 'hhd', 'a', 'A', or i18n parameter modifiers etc. Also double printing of infinity is wrong with regard to case.

  This code contains a bunch of static extensions, and no way to define your own.

- ## postfix

  Allocation policy:
    Automatic
  Format parsing:
    Native
  Double printing:
    Host
  Problems:
    Unimplemented most newer formats. No i18n support. After being checked by the native parser all output is done via. calls to a host sprintf() function.
  User extensions:
    No
  Version:
    1.7.1 of postfix

- ## libretto

  Allocation policy:
    Automatic
  Format parsing:
    Native
  Double printing:
    Host
  Problems:
    Unimplemented most newer formats. No i18n support. After being checked by the native parser all output is done via. calls to a host sprintf() function.
  User extensions:
    No
  Version:
    2.1

- ## libast (formerly libmej)

  Allocation policy:
    Limited
  Format parsing:
    Native
  Double printing:
    Native (terrible)
  Problems:
    Patrick Powell's code, all the problems of the samba variant and lots more.
  User extensions:
    No
  Version:
    0.5

  The printf() like function is a version of Patrick Powell's snprtinf() with a really bad version of a floating point formatter added to it.

- ## librock text processing

  Allocation policy:
    Automatic
  Format parsing:
    Host
  Double printing:
    Host
  Problems:
    Relies directly on host implementation, so crashes are possible if you move code from one platform to another. If asprintf() isn't available on the host, handles very simple formats internally and passes it off to fprintf() if that fails. .
  User extensions:
    No
  Version:
    unknown (2003-02-25)

  Note that before 2003-02-25 the failure path was broken, and would crash.

- ## c2lib

  Allocation policy:
    Automatic/Limited
  Format parsing:
    Host
  Double printing:
    Host
  Problems:
    Relies directly on host implementation, so crashes are possible if you move code from one platform to another. If asprintf() isn't available on the host, it calls snprintf() and will silently truncate input.
  User extensions:
    No
  Version:
    1.4.1

  Note that before 2003-02-25 the failure path was broken, and would crash.

Any corrections or omissions you see in the above, feel free to contact me at the address below

Last modified: Sun Jul 31 00:33:54 EDT 2005