Search code examples
cprintflibcconversion-specifier

Why printf is not able to handle flags, field width and precisions properly?


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?


Solution

  • 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 precision

      Related, 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, and X conversions, the number of digits to appear after the decimal-point character for a, A, e, E, f, and F conversions, the maximum number of significant digits for the g and G 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 [....]