What are the proper rules for printf conversions? - c

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?

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)

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.

Related

Why this formatted output is getting printed while using float?

In this underlying code:
float j=9.01;
printf("%2.3f \n",j);
the output is 9.010, shouldn't it be like 2 character wide reserved for the entire j which includes 3 for the decimal - so it makes the no. before decimal i.e. 9 disappear and only 01 to be printed?
Where am I going wrong in this?
Let's quote the man page:
Field Width
In no case does a nonexistent or small field width cause truncation of a field; if the result of a conversion is wider than the field width, the field is expanded to contain the conversion result.
and
The precision
This gives the minimum number of digits to appear for d, i, o, u, x, and X
conversions, the number of digits to appear after the radix character for
a, A, e, E, f, and F conversions [...]
The field width is too small, but fields are never truncated so that doesn't matter.
The part after the period is clearly the precision, and you ask for three digits.

C printf difference between 0 flag & width attribute and precision flag

I'm currently learning the printf function of libc and I don't understand, what is the difference between:
printf("Test : %010d", 10);
using the 0 flag and 10 as width specifier
and
printf("Test : %.10d", 10);
using 10 as precision specifier
That produce the same output: Test : 0000000010
We'll start with the docs for printf() and I'll highlight their relevant bits.
First 0 padding.
`0' (zero)
Zero padding. For all conversions except n, the converted value is padded on the left with zeros rather than blanks. If a precision is given with a numeric conversion (d, i, o, u, i, x, and X), the 0 flag is ignored.
And then precision.
An optional precision, in the form of a period . followed by an optional digit string. If the digit string is omitted, the precision is taken as zero. This gives the minimum number of digits to appear for d, i, o, u, x, and X conversions, the number of digits to appear after the decimal-point for a, A, e, E, f, and F conversions, the maximum number of significant digits for g and G conversions, or the maximum number of characters to be printed from a string for s conversions.
%010d says to zero-pad to a minimum width of 10 digits. No problem there.
%.10d", because you're using %d, says the minimum number of digits to appear is 10. So the same thing as zero padding. %.10f would behave more like you expected.
I would recommend you use %010d to zero pad. The %.10d form is a surprising feature that might confuse readers. I didn't know about it and I'm surprised it isn't simply ignored.
Both formats produce the same output for positive numbers, but the output differs for negative numbers greater than -1000000000:
printf("Test : %010d", -10); produces -000000010
whereas
printf("Test : %.10d", -10); produces -0000000010
Format %010d pads the output with leading zeroes upto a width of 10 characters.
Format %.10d pads the converted number with leading zeroes upto 10 digits.
The second form is useful if you want to produce no output for value 0 but otherwise produce the normal conversion like %d:
printf("%.0d", 0); // no output
printf("%.0d", 10); // outputs 10
Also note that the initial 0 in the first form is a flag: it can be combined with other flags in any order as in %0+10d which produces +000000010 and it can be used with an indirect width as in printf("%0*d", 10, 10); which produces 0000000010.
There's no difference besides maybe a purely conceptual one.
In the first case you are just filling the blank area with completely independent padding 0 characters. In the second case these zeros are leading zeros created when converting your argument value. (This is admittedly very contrived.)
In any case these zeros look, smell and quack the same.
However, in general case there's one obscure specific situation when precision behaves differently from padded field-width: when you are asking for zero field width and print zero value. When zero precision is used, zero values are simply not printed at all. When zero field-width is used, zero values will appear as usual
printf("%00d\n", 0); // prints '0'
printf("%.0d\n", 0); // prints nothing
Obviously this is also a very contrived situation, since no padding occurs in this case.
In your second case you probably expected 10.0000000000 - but %d is only for integers. The specification says:
For integer specifiers (d, i, o, u, x, X): precision specifies the minimum number of digits to be written.
(Precision is the part started with . , so in your case 10 .)
So, with %.10d you specified at least 10 digits to express the two-digit number, so it is completed with the 8 leading zeroes.
It means that both %010d and %.10d will produce the same result.

%.#s format specifier in printf statement in c

Please explain the output. What does %.#s in printf() mean?
#include<stdio.h>
#include <stdlib.h>
int main(int argc,char*argv[]){
char *A="HELLO";
printf("%.#s %.2s\n",A,A);
return 0;
}
OUTPUT:
#s HE
It's undefined behavior. # in printf format specifier means alternative form, but according to the standard, # is only used together with o, a, A, x, X, e, E, f, F, g, G, not including s.
C11 §7.21.6.1 The fprintf function Section 6
# The result is converted to an ‘‘alternative form’’. For o conversion, it increases
the precision, if and only if necessary, to force the first digit of the result to be a
zero (if the value and precision are both 0, a single 0 is printed). For x (or X)
conversion, a nonzero result has 0x (or 0X) prefixed to it. For a, A, e, E, f, F, g, and G conversions, the result of converting a floating-point number always
contains a decimal-point character, even if no digits follow it. (Normally, a decimal-point character appears in the result of these conversions only if a digit follows it.) For g and G conversions, trailing zeros are not removed from the result. For other conversions, the behavior is undefined.
For example, on my machine, output is different: %.0#s HE
%.1s is used to print the first character of the string
%.2s is used to print the first two characters of the string
%.3s is used to print the first three characters of the string and so on
where # : alternative form of the conversion is performed is a flag which have an optional usage with the format parameter in printf() and fprintf() functions etc.
But as #Yu Hao said # is only used together with o, a, A, x, X, e, E, f, F, g, G, not including s.
in your case %.#s usage is Wrong.
Example usage from reference given by #WhozCraig :
printf("Hexadecimal:\t%x %x %X %#x\n", 5, 10, 10, 6);
printf("Octal:\t%o %#o %#o\n", 10, 10, 4);
I agree with Yu Hao's answer that it is undefined behavior, but I think the reason is different. Yes, the # character works as a flag to convert the result to an alternative format. Yes, the # flag is undefined for strings. But in this case, the # is not a flag, it's a precision. It's still undefined, but the reason is different
The C11 standard at §6.21.6.1 says that the % sign is followed in sequence by:
Zero or more flags (including #)
An optional minimum field width
An optional precision
An optional length modifier
A conversion specifier character
Except for the conversion specifier, these are all optional. But the order in which they appear is always as above. So flag, if present, has to be first, immediately after the % character. Here what follows the % is not something indicating a flag, it is a period: %., indicating precision.
When you have %.# in your format string for printf(), the period indicates that the following character is the precision for the conversion specification that follows. I.e., the # in your code specifies the precision for the string s, not a flag. To be a flag, it would have to directly follow the % character, without the intervening period.
With regard to precision, the C standard §7.21.6.1 says this:
The precision takes the form of a period (.) followed either by an asterisk *
(described later) or by an optional decimal integer; if only the period is specified,
the precision is taken as zero. If a precision appears with any other conversion
specifier, the behavior is undefined.
Since in your format string you have %.#s, and # is neither an asterisk * nor a decimal integer, the result is undefined.
So to be extremely exact about why your code is undefined, I think it's because the # character appears in place of a legal precision, not because it is an illegal flag for the %s conversion. It would be illegal as a flag, of course, but that's not what is precisely (har har) happening here.

Wrong output from printf of a number

int main()
{
double i=4;
printf("%d",i);
return 0;
}
Can anybody tell me why this program gives output of 0?
When you create a double initialised with the value 4, its 64 bits are filled according to the IEEE-754 standard for double-precision floating-point numbers. A float is divided into three parts: a sign, an exponent, and a fraction (also known as a significand, coefficient, or mantissa). The sign is one bit and denotes whether the number is positive or negative. The sizes of the other fields depend on the size of the number. To decode the number, the following formula is used:
1.Fraction × 2Exponent - 1023
In your example, the sign bit is 0 because the number is positive, the fractional part is 0 because the number is initialised as an integer, and the exponent part contains the value 1025 (2 with an offset of 1023). The result is:
1.0 × 22
Or, as you would expect, 4. The binary representation of the number (divided into sections) looks like this:
0 10000000001 0000000000000000000000000000000000000000000000000000
Or, in hexadecimal, 0x4010000000000000. When passing a value to printf using the %d specifier, it attempts to read sizeof(int) bytes from the parameters you passed to it. In your case, sizeof(int) is 4, or 32 bits. Since the first (rightmost) 32 bits of the 64-bit floating-point number you supply are all 0, it stands to reason that printf produces 0 as its integer output. If you were to write:
printf("%d %d", i);
Then you might get 0 1074790400, where the second number is equivalent to 0x40100000. I hope you see why this happens. Other answers have already given the fix for this: use the %f format specifier and printf will correctly accept your double.
Jon Purdy gave you a wonderful explanation of why you were seeing this particular result. However, bear in mind that the behavior is explicitly undefined by the language standard:
7.19.6.1.9: If a conversion specification is invalid, the behavior is undefined.248) If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
(emphasis mine) where "undefined behavior" means
3.4.3.1: behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements
IOW, the compiler is under no obligation to produce a meaningful or correct result. Most importantly, you cannot rely on the result being repeatable. There's no guarantee that this program would output 0 on other platforms, or even on the same platform with different compiler settings (it probably will, but you don't want to rely on it).
%d is for integers:
int main()
{
int i=4;
double f = 4;
printf("%d",i); // prints 4
printf("%0.f",f); // prints 4
return 0;
}
Because the language allows you to screw up and you happily do it.
More specifically, '%d' is the formatting for an int and therefore printf("%d") consumes as many bytes from the arguments as an int takes. But a double is much larger, so printf only gets a bunch of zeros. Use '%lf'.
Because "%d" specifies that you want to print an int, but i is a double. Try printf("%f\n"); instead (the \n specifies a new-line character).
The simple answer to your question is, as others have said, that you're telling printf to print a integer number (for example a variable of the type int) whilst passing it a double-precision number (as your variable is of the type double), which is wrong.
Here's a snippet from the printf(3) linux programmer's manual explaining the %d and %f conversion specifiers:
d, i The int argument is converted to signed decimal notation. 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. The default precision is 1.
When 0 is printed with an explicit precision 0, the output is
empty.
f, F The double argument is rounded and converted to decimal notation
in the style [-]ddd.ddd, where the number of digits after the
decimal-point character is equal to the precision specification.
If the precision is missing, it is taken as 6; if the precision
is explicitly zero, no decimal-point character appears. If a
decimal point appears, at least one digit appears before it.
To make your current code work, you can do two things. The first alternative has already been suggested - substitute %d with %f.
The other thing you can do is to cast your double to an int, like this:
printf("%d", (int) i);
The more complex answer(addressing why printf acts like it does) was just answered briefly by Jon Purdy. For a more in-depth explanation, have a look at the wikipedia article relating to floating point arithmetic and double precision.
Because i is a double and you tell printf to use it as if it were an int (%d).
#jagan, regarding the sub-question:
What is Left most third byte. Why it is 00000001? Can somebody explain?"
10000000001 is for 1025 in binary format.

Why does "%.3i" print leading zeros?

There was a bit of a surprise with some code today. I was compiling it on AIX, with the warning level set to anal to see what rogue issues might be lurking. Something new crawled out of the code.
1540-2837 (W) '0' flag is disregarded when combined with
precision and 'i' printf format.
After looking at the offending line, I put together a little program to reproduce it. Testing it on several platforms showed that it is not AIX specific.
The first printf below mimics what was found in the program.
#include <stdio.h>
int main(void)
{
int x = 3;
printf("Format 0.3i <%0.3i>\n", x); // prints 003, and AIX does a warning
printf("Format .3i <%.3i>\n", x); // prints 003, with no warning
printf("Format 3i <%3i>\n", x); // prints 3, with no warning.
return 0;
}
Normally, if leading zeros were needed, a format of "03i" would do the job nicely.
What does "%.3i" really mean here?
Why does it have the behavior that it does?
.X, where x is a number means "print at least X" digits, so %.3i means print at least 3 digits. If the number is less than 100, it is left padded with zeros.
From a doc on printf
"For integer specifiers (d, i, o, u, x, X): precision specifies the minimum number of digits to be written. If the value to be written is shorter than this number, the result is padded with leading zeros. The value is not truncated even if the result is longer. A precision of 0 means that no character is written for the value 0."
There is another concept, "width" (e.g. "%3i") which causes a certain number of characters to be output (not necessarily digits, and the 0 specified is used to say that those characters should be 0s, as in "003" and not spaces, as in " 3")
From man 3 printf:
If a precision is given with a
numeric conversion (d, i, o, u, x, and
X), the 0 flag is ignored.
The . is specifying the precision and therefore the 0 is ignored. As to the "Why?" of it, you'd have to ask the authors of the C standard :)

Resources