Thunderpurtz
Thunderpurtz

Reputation: 199

What are the proper rules for printf conversions?

I have this function call for printf:

printf("%-+05.6d", 133);

With this output:

+000133

I'm having trouble with the rules of how the printf flags interact with each other since it seems they are given conflicting rules.

According to the man(man 3 printf):

0

The value should be zero padded. For d, i, o, u, x, X, a, A, e, E, f, F, g, and G conversions, the converted value is padded on the left with zeros rather than blanks. If the 0 and - flags both appear, the 0 flag is ignored. If a precision is given with a numeric conversion (d, i, o, u, x, and X), the 0 flag is ignored. For other conversions, the behavior is undefined.

So according to this, the 0 flag should be ignored since there is both a '-' flag and a precision specified, yet it is still printing 0's.

According to the man for diouxX conversions:

The precision, if any, gives the minimum number of digits that must appear; if the converted value requires fewer digits, it is padded on the left with zeros.

So with both of these rules, it would seem that specific diouxX conversion rule applies here since 0's are still being printed, but then why does the man say the 0's get ignored?

Since precision is applied here, shouldn't the '0' flag be ignored and padded with spaces instead?

Upvotes: 0

Views: 169

Answers (2)

luther
luther

Reputation: 5564

Based on the documentation that you quote, the 0 in the format is ignored, meaning it has no effect on whether there are zeros in the output. Then, you provide a precision of .6 with an integer format, which means the result must show 6 or more digits. The zeros you see are needed to fill up that minimum number of digits.

If the format did not include - or .6, the 05 would mean that the entire number would take up at least than 5 characters, padded by zeros, so the output would be +0133.

Upvotes: 1

David C. Rankin
David C. Rankin

Reputation: 84579

You have a mess. The 0 is ignored, try it:

printf("%-+5.6d", 133);

Output

+000133

The problem you have is there are multiple overriding flags specified. You correct cite that a - (left justified) overrides the 0. The sign flag + provides a space for either +/- before the string on all occasions.

The next conflict is 5.6. You specify a field-width modifier of 5, but then specify the precision as 6. For d, i, o, u, x, and X conversions the precision specifies the number of digits that will appear. (see C11 Standard -7.21.6.1 The fprintf function) So while not specifically stated, the precision being greater than the field-width effectively overrides the field width resulting in 6-digits in addition to the + sign being printed for 133.

So the crux of the issue is "Why if - overrides the 0 flag are 0s still printed?" Here there are some technical hairs to be split. Since you have specified - (left justified) and both a field-width and precision, the 0 is ignored but you have stated that 6-digits shall be printed and the result will be left-justified. So you get 0s based on the precision and then total number of digits is left-justified with explicit +/- being provided for the sign.

Remove the precision and you will see the effect of - overriding 0:

printf("%-+05.d", 133);

Output:

+133

(there is an empty following the final 3 to make a total field-width of 5)

(note: -- can you rely on this being completely portable? -- probably not, there is likely a bit of implementation defined leeway left in the standard for flag sequence interpretation that may result in a slightly different ordering of flags with some compilers)

Upvotes: 3

Related Questions