c – printf() formatting for hexadecimal

c – printf() formatting for hexadecimal

The # part gives you a 0x in the output string. The 0 and the x count against your 8 characters listed in the 08 part. You need to ask for 10 characters if you want it to be the same.

int i = 7;

printf(%#010xn, i);  // gives 0x00000007
printf(0x%08xn, i);  // gives 0x00000007
printf(%#08xn, i);   // gives 0x000007

Also changing the case of x, affects the casing of the outputted characters.

printf(%04x, 4779); // gives 12ab
printf(%04X, 4779); // gives 12AB

The 0x counts towards the eight character count. You need %#010x.

Note that # does not append the 0x to 0 – the result will be 0000000000 – so you probably actually should just use 0x%08x anyway.

c – printf() formatting for hexadecimal

The %#08X conversion must precede the value with 0X; that is required by the standard. Theres no evidence in the standard that the # should alter the behaviour of the 08 part of the specification except that the 0X prefix is counted as part of the length (so you might want/need to use %#010X. If, like me, you like your hex presented as 0x1234CDEF, then you have to use 0x%08X to achieve the desired result. You could use %#.8X and that should also insert the leading zeroes.

Try variations on the following code:

#include <stdio.h>

int main(void)
{
    int j = 0;
    printf(0x%.8X = %#08X = %#.8X = %#010xn, j, j, j, j);
    for (int i = 0; i < 8; i++)
    {
        j = (j << 4) | (i + 6);
        printf(0x%.8X = %#08X = %#.8X = %#010xn, j, j, j, j);
    }
    return(0);
}

On an RHEL 5 machine, and also on Mac OS X v10.7.5 (Lion), the output was:

0x00000000 = 00000000 = 00000000 = 0000000000
0x00000006 = 0X000006 = 0X00000006 = 0x00000006
0x00000067 = 0X000067 = 0X00000067 = 0x00000067
0x00000678 = 0X000678 = 0X00000678 = 0x00000678
0x00006789 = 0X006789 = 0X00006789 = 0x00006789
0x0006789A = 0X06789A = 0X0006789A = 0x0006789a
0x006789AB = 0X6789AB = 0X006789AB = 0x006789ab
0x06789ABC = 0X6789ABC = 0X06789ABC = 0x06789abc
0x6789ABCD = 0X6789ABCD = 0X6789ABCD = 0x6789abcd

Im a little surprised at the treatment of 0; Im not clear why the 0X prefix is omitted, but with two separate systems doing it, it must be standard. It confirms my prejudices against the # option.


The treatment of zero is according to the standard.

ISO/IEC 9899:2011 §7.21.6.1 The fprintf function

¶6 The flag characters and their meanings are:

# The result is converted to an alternative form. … For x (or X)
conversion, a nonzero result has 0x (or 0X) prefixed to it. …

(Emphasis added.)


Note that using %#X will use upper-case letters for the hex digits and 0X as the prefix; using %#x will use lower-case letters for the hex digits and 0x as the prefix. If you prefer 0x as the prefix and upper-case letters, you have to code the 0x separately: 0x%X. Other format modifiers can be added as needed, of course.

For printing addresses, use the <inttypes.h> header and the uintptr_t type and the PRIXPTR format macro:

#include <inttypes.h>
#include <stdio.h>

int main(void)
{
    void *address = &address;  // &address has type void ** but it converts to void *
    printf(Address 0x%.12 PRIXPTR n, (uintptr_t)address);
    return 0;
}

Example output:

Address 0x7FFEE5B29428

Choose your poison on the length — I find that a precision of 12 works well for addresses on a Mac running macOS. Combined with the . to specify the minimum precision (digits), it formats addresses reliably. If you set the precision to 16, the extra 4 digits are always 0 in my experience on the Mac, but theres certainly a case to be made for using 16 instead of 12 in portable 64-bit code (but youd use 8 for 32-bit code).

Leave a Reply

Your email address will not be published.