Why is 0 (zero) printed without leading "0x" with C printf format "%#x"?

12,669

The standard seems to be written this way:

  • %#x and %#o try to guarantee that the output can be parsed correctly using strtol with base = 0.

  • In these cases, the # flag adds as few extra characters as possible. For example, 0 is printed as 0 because there is no need to add the extra 0x. This makes a lot of sense if you do not specify the minimum field width and 0-padding.

  • If you wanted to add 0x always, you could often simply write something like 0x%x. Hence %#x would seem to be useful only in those special cases in which you really want the special handling of 0. But the pre-pending of 0x doesn't work well with default field width specifiers eg) 0x%12xis right justified by blanks between the 0x and hex digits, which is unlikely to be what's wanted in that case. For this case an extra preparatory pass with sprintf would be required, so a hex string like "0x2ac2" can be white space right justified with something like printf( "%12s", hexstr); Fortunately justifying with 0 rather than spaces using something like printf( "0x%012x", hexstr); works as expected producing valid hex digits for a parser.

Now the way %#x is specified to work makes a lot of sense in isolation. And the way something like %010x is specified to work makes a lot of sense in isolation. You are combining these two modifiers, and the end result is, arguably, strange. For another application, like auto generating neat C code to initialise tables, having 0, rather than 0x0 is not an issue.

But there is no need to combine %#x and %010x. You could just write 0x%08x to do what you want.

Share:
12,669
David Poole
Author by

David Poole

Firmware engineer working on routers with Cradlepoint in Boise, Idaho. Work in C, Python, Linux kernel, GIS, low level firmware.

Updated on June 13, 2022

Comments

  • David Poole
    David Poole almost 2 years

    Background: I have a number of scripts that parse log files looking for hex numbers by finding the leading "0x". Our embedded C library changed to a new printf. The new printf is more standards compliant than our previous and my scripts broke.

    On a Linux box:

    #include <stdio.h>
    int main( void )
    {
        printf( "%#010x\n", 0 );
        printf( "%#010x\n", 1 );
        return 0;
    }
    

    Output (using glibc) is:

    0000000000
    0x00000001
    

    Output on our firmwware was:

    0x00000000
    0x00000001
    

    From printf(3), on the '#' flag character: "For x and X conversions, a nonzero result has the string "0x" (or "0X" for X conversions) prepended to it."

    I'm curious why. Without digging through the C standards documents or buying lunch for standards committee members, why not a leading 0x on a zero valued argument?