Printing numbers using printf
The printf
family of functions take a format string, containing both regular text and special formatting specifiers, and at least as many additional arguments as there are formatting specifiers in the format string. Each formatting specifier is supposed to indicate the type of the corresponding argument. Then, via compiler-specific magic, that argument value is accessed and formatted as directed.
C originally only had char
, short
, int
, and long
integer types (in signed and unsigned versions). So the original set of format specifiers only supported interpreting arguments as one of those types.
Fixed-size integers
With the rise of <stdint.h>
, it’s common to want to print a uint32_t
, or an int64_t
, or similar. But if you don’t know what type uint32_t
is, how do you know what format specifier to use? C99 defines macros in <inttypes.h>
that expand to suitable format specifiers. For example, if uint32_t
is actually unsigned long
, then the PRIu32
macro might be defined as "lu"
.
uint32_t u = 3141592654; printf("u: %" PRIu32 "\n", u);
Unfortunately <inttypes.h>
isn’t available everywhere. So for now, we have to reimplement it ourselves. The new mfbt header mfbt/IntegerPrintfMacros.h
, available via #include "mozilla/IntegerPrintfMacros.h"
, provides all the PRI*
macros exposed by <inttypes.h>
: by delegating to that header when present, and by reimplementing it when not. Go use it. (Note that all Mozilla code has __STDC_LIMIT_MACROS
, __STDC_FORMAT_MACROS
, and __STDC_CONST_MACROS
defined, so you don’t need to do anything special to get the macros — just #include "mozilla/IntegerPrintfMacros.h"
.)
Limitations
The implementations of <inttypes.h>
in all the various standard libraries/compilers we care about don’t always provide definitions of these macros that are free of format string warnings. This is, of course, inconceivable. We can reimplement the header as needed to fix these problems, but it seemed best to avoid that til someone really, really cared.
<inttypes.h>
also defines format specifiers for fixed-width integers, for use with the scanf
family of functions that read a number from a string. IntegerPrintfMacros.h
does not provide these macros. (At least, not everywhere. You are not granted any license to use them if they happen to be incidentally provided.) First, it’s actually impossible to implement the entire interface for the Microsoft C runtime library. (For example: no specifier will write a number into an unsigned char*
; this is necessary to implement SCNu8
.) Second, sscanf
is a dangerous function, because if the number in the input string doesn’t fit in the target location, anything (undefined behavior, that is) can happen.
uint8_t u; sscanf("256", "%" SCNu8, &u); // I just ate ALL YOUR COOKIES
IntegerPrintfMacros.h
does implement imaxabs
, imaxdiv
, strtoimax
, strtoumax
, wcstoimax
, and wcstoumax
. I mention this only for completeness: I doubt any Mozilla code needs these.