Why do I have to specify data type each time in C to printf() and scanf()?

Solution 1:

Because there's no portable way for a variable argument functions like scanf and printf to know the types of the variable arguments, not even how many arguments are passed.

See C FAQ: How can I discover how many arguments a function was actually called with?


This is the reason there must be at least one fixed argument to determine the number, and maybe the types, of the variable arguments. And this argument (the standard calls it parmN, see C11(ISO/IEC 9899:201x) §7.16 Variable arguments ) plays this special role, and will be passed to the macro va_start. In another word, you can't have a function with a prototype like this in standard C:

void foo(...);

Solution 2:

The reason why the compiler can not provide the necessary information is simply, because the compiler is not involved here. The prototype of the functions doesn't specify the types, because these functions have variable types. So the actual data types are not determined at compile time, but at runtime. The function then takes one argument from the stack, after the other. These values don't have any type information associated with it, so the only way, the function knows how to interpret the data is, by using the caller provided information, which is the format string.

The functions themselves don't know which data types are passed in, nor do they know the number of arguments passed, so there is no way that printf can decide this on it's own.

In C++ you can use operator overloading, but this is an entire different mechanism. Because here the compiler chooses the appropriate function based on the datatypes and available overloaded function.

To illustrate this, printf, when compiled looks like this:

 push value1
 ...
 push valueN
 push format_string
 call _printf

And the prototype of printf is this:

int printf ( const char * format, ... );

So there is no type information carried over, except what is provided in the format string.

Solution 3:

printf is not an intrinsic function. It's not part of the C language per se. All the compiler does is generate code to call printf, passing whatever parameters. Now, because C does not provide reflection as a mechanism to figure out type information at run time, the programmer has to explicitly provide the needed info.

Solution 4:

Compiler may be smart, but functions printf or scanf are stupid - they do not know what is the type of the parameter do you pass for every call. This is why you need to pass %s or %d every time.

Solution 5:

The first parameter is a format string. If you're printing a decimal number, it may look like:

  • "%d" (decimal number)
  • "%5d" (decimal number padded to width 5 with spaces)
  • "%05d" (decimal number padded to width 5 with zeros)
  • "%+d" (decimal number, always with a sign)
  • "Value: %d\n" (some content before/after the number)

etc, see for example Format placeholders on Wikipedia to have an idea what format strings can contain.

Also there can be more than one parameter here:

"%s - %d" (a string, then some content, then a number)