Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c

printf

hex

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?

like image 883
David Poole Avatar asked Dec 14 '11 23:12

David Poole


People also ask

What is formatting string in C?

The Format specifier is a string used in the formatted input and output functions. The format string determines the format of the input and output. The format string always starts with a '%' character.

How do you printf in hexadecimal?

To print integer number in Hexadecimal format, "%x" or "%X" is used as format specifier in printf() statement. "%x" prints the value in Hexadecimal format with alphabets in lowercase (a-f). "%X" prints the value in Hexadecimal format with alphabets in uppercase (A-F).


1 Answers

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.

like image 141
Jukka Suomela Avatar answered Oct 14 '22 23:10

Jukka Suomela