272

Why, when printing a number in hexadecimal as an 8 digit number with leading zeros, does %#08X not display the same result as 0x%08X?

When I try to use the former, the 08 formatting flag is removed, and it doesn't work with just 8.

1
  • 3
    Do you mean 0x%.8X ? That will lead-fill with zeros. (the 0x is just a preamble, but your likely already aware of that).
    – WhozCraig
    Commented Feb 6, 2013 at 16:23

5 Answers 5

406

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("%#010x\n", i);  // gives 0x00000007
printf("0x%08x\n", i);  // gives 0x00000007
printf("%#08x\n", 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
7
  • The top line outputs 14F0x00000007 for me. The second and third work as written. Commented Jan 6, 2014 at 3:15
  • @quantumpotato - That's... odd. The first and third lines are identical with the exception of the number of 0's they should produce. What was your compiler/system/line of code that produced this? Did you have any lines proceeding the one that printed 14F?
    – Mike
    Commented Jan 8, 2014 at 14:23
  • 32
    Note that if i = 0;, the versions using %# will not include the 0x prefix. Commented Nov 19, 2014 at 8:13
  • 1
    but how about the hex: 0x43A66C31C68491C0 I have tried the following: __int64 int64 = 0x43A66C31C68491C0; printf_s("%#15X %d",int64,int64); But the output is 0XC68491C0, not 0x43A66C31C68491C0
    – 123iamking
    Commented May 7, 2016 at 4:16
  • About the hex 0x43A66C31C68491C0 above, I have solve it, the solution is 0x%I64X , not %#15X
    – 123iamking
    Commented May 7, 2016 at 4:30
68

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.

1
  • 3
    Thanks for pointing out that # does not prepend "0x" to "0"! Commented Oct 11, 2020 at 22:18
43

The %#08X conversion must precede the value with 0X; that is required by the standard. There's 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 = %#010x\n", j, j, j, j);
    for (int i = 0; i < 8; i++)
    {
        j = (j << 4) | (i + 6);
        printf("0x%.8X = %#08X = %#.8X = %#010x\n", 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

I'm a little surprised at the treatment of 0; I'm 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 there's certainly a case to be made for using 16 instead of 12 in portable 64-bit code (but you'd use 8 for 32-bit code).

13

# causes 0x (or 0X for %#X) to be prepended to the output unless the value is 0, so you should not use # if you want 0x to always appear in the output.

You can use the width field combined with the 0 flag to produce leading zeroes: %08x pads the number with leading zeroes to a width of 8. If you want consistent output for all 32-bit values, use "0x08x".

You could also use the precision field: %.8x pads the number with leading zeroes to a total of 8 digits. Hence you can also use "0x%.8x" for your purpose.

These conversion specifications would differ if a prefix is generated as part of the conversion, such as 0x for # or - for negative numbers in signed conversions, whose length is counted for the width but not for the precision specifier. Furthermore, the precision field can be combined with the width field:

printf("|%10x|", 256)      // outputs |       100|
printf("|%010x|", 256)     // outputs |0000000100|
printf("|%#010x|", 256)    // outputs |0x00000100|

printf("|%10.8x|", 256)    // outputs |  00000100|
printf("|%#10.8x|", 256)   // outputs |0x00000100|
printf("|0x%.8x|", 256)    // outputs |0x00000100|

printf("|%10x|", 0)        // outputs |         0|
printf("|%010x|", 0)       // outputs |0000000000|
printf("|%#010x|", 0)      // outputs |0000000000|

printf("|%10.8x|", 0)      // outputs |  00000000|
printf("|%#10.8x|", 0)     // outputs |  00000000|
printf("|0x%.8x|", 0)      // outputs |0x00000000|

I would recommend using the last one: "0x%.8x".

0

You could always use "%p" in order to display 8 bit hexadecimal numbers.

int main (void)
{
    uint8_t a;
    uint32_t b;
    a = 15;
    b = a << 28;
    printf("%p", b);
    return 0;
}

Output:

0xf0000000
5
  • What environment defines uint8_t and uint32_t? Commented Apr 26, 2021 at 12:31
  • 1
    Starting off with #include <stdio.h> and #include <stdint.h> may be sufficient. Commented Apr 26, 2021 at 13:29
  • 1
    With that content, on Linux, gcc -x c Hexprint_p.c results in warning: format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘uint32_t’ {aka ‘unsigned int’} [-Wformat=]. Commented Apr 26, 2021 at 13:30
  • 1
    The output of %p is implementation dependent and passing an int32_t for %p has undefined behavior. Definitely not a good solution.
    – chqrlie
    Commented Apr 27, 2021 at 9:54
  • In my implementation, works perfectly! However the result is trunk at left for zeros (printf("Sl_1: %p\n", 0x0123) => Sl_1: 0x123)
    – tontonCD
    Commented Mar 27, 2022 at 16:20

Not the answer you're looking for? Browse other questions tagged or ask your own question.