cprintfvariadic-functions

More placeholders than arguments for 'printf'


I know that we can do more arguments than placeholders when using printf, in which case, the excessive arguments are simply ignored:

printf("%s", "Hello friend!\n", "Long time no see!\n"); // Prints Hello friend!

By a chance, I found the opposite way works too, that is, we can do more placeholders than arguments. See below:

printf("%d"); // Prints a different number each time executed

I wonder:

  1. What is the number it's printing? Is it an undefined behavior?
  2. Why doesn't the compiler issue an error for this? What functionality could it possibly serve?

Solution

  • By a chance, I found the opposite way works too, that is, we can do more placeholders than arguments,…

    You “can” do this because the C standard does not forbid programs from doing it. However, the C standard does not define the behavior. It is generally considered an error to do this except in extraordinary circumstances, such as testing protections against program exploits. (For example, if a compiler feature for reporting problems in printf format strings has been designed, it would be proper to write code like this for the purpose of testing that feature.)

    What is the number it's printing? is it an undefined behavior?

    Yes, it is undefined behavior.

    The most common behavior is that printf prints whatever number is in the place where it would expect to find the argument that should have been passed. For example, if the argument would have been passed in general register R5, printf may print the number that is in R5, which will be some number left over from previous operations in the program.

    However, optimization by the compiler may change this.

    Why don't issue a compiler error for this?

    Some compilers do warn about this, especially if you enable more than the default warnings.1 It requires interpreting the format string, which is extra work that is not necessary in a basic compiler, so it is an advanced feature. And, of course, it is possible only if the compiler can see the format string, which it may not if the string is passed via a variable instead of via a string literal.

    what functionality could it possible serve?

    There is no ordinary use for this.

    Footnote

    1 The default warnings in the common main compilers are inadequate, and you should almost always enable more warnings and elevate them to errors, so that you learn to write clean code to start with. With Clang, start with -Wmost -Werror. With GCC, start with -Wall -Werror. With MSVC, start with /W3 /WX.