问题
I'm trying to discover all capabilities of printf and I have tried this :
printf("Test:%+*0d", 10, 20);
that prints
Test:%+100d
I have use first the flag +
, then the width *
and the re-use the flag 0
.
Why it's make this output ? I purposely used printf()
in a bad way but I wonder why it shows me the number 100?
回答1:
This is because, you're supplying syntactical nonsense to the compiler, so it is free to do whatever it wants. Related reading, undefined behavior.
Compile your code with warnings enabled and it will tell you something like
warning: unknown conversion type character ‘0’ in format [-Wformat=]
printf("Test:%+*0d", 10, 20);
^
To be correct, the statement should be either of
printf("Test:%+*.0d", 10, 20); // note the '.'
where, the
0
is used as a precisionRelated, quoting the
C11
, chapter §7.21.6.1, (emphasis mine)An optional precision that gives the minimum number of digits to appear for the
d
,i
,o
,u
,x
, andX
conversions, the number of digits to appear after the decimal-point character fora
,A
,e
,E
,f
, andF
conversions, the maximum number of significant digits for theg
andG
conversions, or the maximum number of bytes to be written for s conversions. 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.printf("Test:%+0*d", 10, 20);
where, the
0
is used as a flag. As per the syntax, all the flags should appear together, before any other conversion specification entry, you cannot just put it anywhere in the conversion specification and expect the compiler to follow your intention.Again, to quote, (and my emphasis)
Each conversion specification is introduced by the character
%
. After the%
, the following appear in sequence:- Zero or more flags (in any order) [...]
- An optional minimum field width [...]
- An optional precision [...]
- An optional length modifier [...]
- A conversion specifier [....]
回答2:
Your printf
format is incorrect: the flags must precede the width specifier.
After it handles *
as the width specifier, printf
expects either a .
or a length modifier or a conversion specifier, 0
being none of these, the behavior is undefined.
Your library's implementation of printf
does something bizarre, it seems to handle *
by replacing it with the actual width argument... A side effect of the implementation. Others may do something else, including aborting the program. Such a format error would be especially risky if followed by a %s
conversion.
Changing your code to printf("Test:%+0*d", 10, 20);
should produce the expected output:
Test:+000000020
回答3:
In complement of Sourav Ghosh's answer; an important notion is that of undefined behavior, which is tricky. Be sure to read Lattner's blog: What Every C Programmer Should Know About Undefined Behavior. See also this.
So, leaving on purpose (or perhaps depending upon) some undefined behavior in your code is intentional malpractice. Don't do that. In the very rare cases you want to do that (I cannot see any), please document it and justify yourself in some comment.
Be aware that if indeed printf
is implemented by the C standard library, it can be (and often is) specially handled by the compiler (with GCC and GNU libc, that magic might happens using internally __builtin_printf
)
The C99 & C11 standards are partially specifying the behavior of printf
but does leave some undefined behavior cases to ease the implementation. You are unlikely to full understand or be able to mimic these cases. And the implementation itself could change (for example, on my Debian Linux, an upgrade of libc
might change the undefined behavior of printf
)
If you want to understand more printf
study the source of some C standard library implementation (e.g. musl-libc, whose code is quite readable) and of the GCC implementation (assuming a Linux operating system).
But maintainers of GNU libc and of GCC (& even of the Linux kernel, thru syscalls) stay free to change the undefined behavior (of printf
and anything else)
In practice, always compile with gcc -Wall
(and probably also -g
) if using GCC. Don't accept any warnings (so improve your own code till you get none).
来源:https://stackoverflow.com/questions/40575096/why-printf-is-not-able-to-handle-flags-field-width-and-precisions-properly