Why use% 8.8 over% 08 in printf format string?

Just came across some (very) inherited code (originally written as C, but now compiled as C ++) and using a width specifier for a zero line spacing

void main() { unsigned long val = 2413; printf("V1: %08lu \n", val); printf("V2: %8.8lu \n", val); } 

The results are identical.

 V1: 00002413 V2: 00002413 

So why use V2? Was there any inherited aspect of std lib from days?

Compiler Details: Microsoft (R) C / C ++ Compiler Optimization Version 19.10.25019 for x86

+5
source share
4 answers

There is no difference for unsigned integer types. For negative values ​​of signed integer types, you will see a different output

 long val = -2413; printf("V1: %08ld\n", val); printf("V2: %8.8ld\n", val); V1: -0002413 V2: -00002413 

The .8 %8.8ld indicates the minimum number of digits displayed. Sign - not considered a number. For this reason, the second version should always print 8 digits. If the value is negative, the - sign will have no choice but to become the 9th character, which will violate the required field width 8.

In version %08ld there is no need to print at least 8 digits, so the - character occupies one character in a field width of 8 and only 7 digits are printed.

http://coliru.stacked-crooked.com/a/fc9022cc0ef3e097

+16
source

As I noticed in the comment, with strings, there is a difference between %8s and %8.8s - the latter truncates if the string is longer than 8 . There is one more difference; 0 not a valid modifier for %s . %8.8lu is actually no different from %.8lu ; there is not much difference between %.8lu and %08lu , although 0 older as well . was added to the C90 (so pretty old these days). There is a difference between %.8ld and %08ld , although when the values ​​are negative.

Here is some code that illustrates some of the vagaries of integer formats for printf() - for both signed and unsigned values. Please note that if you have %8.6lu and not %8.8lu (similarly for a signed one), you will get interesting differences.

 #include <stdio.h> static void test_ul(void) { char *fmt[] = { "%08lu", "%8.8lu", "%.8lu", "%8.6lu", "%6.8lu", }; enum { NUM_FMT = sizeof(fmt) / sizeof(fmt[0]) }; unsigned long val[] = { 2413LU, 234512349LU }; enum { NUM_VAL = sizeof(val) / sizeof(val[0]) }; for (int i = 0; i < NUM_FMT; i++) { for (int j = 0; j < NUM_VAL; j++) { printf("%8s: [", fmt[i]); printf(fmt[i], val[j]); puts("]"); } } } static void test_sl(void) { char *fmt[] = { "%08ld", "%8.8ld", "%.8ld", "%8.6ld", "%6.8ld", }; enum { NUM_FMT = sizeof(fmt) / sizeof(fmt[0]) }; long val[] = { +2413L, -2413L, +234512349L, -234512349L }; enum { NUM_VAL = sizeof(val) / sizeof(val[0]) }; for (int i = 0; i < NUM_FMT; i++) { for (int j = 0; j < NUM_VAL; j++) { printf("%8s: [", fmt[i]); printf(fmt[i], val[j]); puts("]"); } } } int main(void) { test_ul(); test_sl(); return 0; } 

Output (GCC 7.1.0 on macOS Sierra 10.12.5):

  %08lu: [00002413] %08lu: [234512349] %8.8lu: [00002413] %8.8lu: [234512349] %.8lu: [00002413] %.8lu: [234512349] %8.6lu: [ 002413] %8.6lu: [234512349] %6.8lu: [00002413] %6.8lu: [234512349] %08ld: [00002413] %08ld: [-0002413] %08ld: [234512349] %08ld: [-234512349] %8.8ld: [00002413] %8.8ld: [-00002413] %8.8ld: [234512349] %8.8ld: [-234512349] %.8ld: [00002413] %.8ld: [-00002413] %.8ld: [234512349] %.8ld: [-234512349] %8.6ld: [ 002413] %8.6ld: [ -002413] %8.6ld: [234512349] %8.6ld: [-234512349] %6.8ld: [00002413] %6.8ld: [-00002413] %6.8ld: [234512349] %6.8ld: [-234512349] 
+6
source

These two are equivalent when used with unsigned long (/ integers), as you read in ref.

 printf("V1: %08lu \n", val); 
Flag

0 will leave a number with zeros (0) instead of spaces when padding is specified (see width specifier).

8 will be number in "Minimum number of characters to print." If the value to be printed is less than this number, the result will be filled with spaces. The value is not truncated, even if the result is larger. "


Now this:

 printf("V2: %8.8lu \n", val); 

saves the effects of 8 as number , but adds .8 as .number in "For integer specifiers (d, i, o, u, x, X): precision sets the minimum number of digits to write. If the value to be written is shorter of this number, the result will be supplemented with leading zeros. The value is not truncated even if the result is longer. An accuracy of 0 means that no character is written for the value 0. "


PS: Standard C ++ should produce a diagnostic error as such:

 prog.cc:3:11: error: '::main' must return 'int' void main() ^ 

however, even Stroustrup himself says that it is "not and never was C ++, and it was not even C".

+4
source

Actually, it doesn’t make any difference between %08 and %8.8 , if you do not enter decimal numbers, then there is a difference. It all depends on how the user likes it. This is just a preference.

0
source

Source: https://habr.com/ru/post/1268854/


All Articles