Why does printf require a required parameter?

The definition of the printf function in C is:

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

      

The same goes for scanf

many similar functions, where a variable number of arguments are controlled.

Why is there a required parameter _Format

?

+3


source to share


5 answers


The format string is required because macros work with variable C arguments depending on at least one argument present and using it to find others.

In particular, to read other variables, you use va_start



(then va_arg

several times, once for each variable argument you want to read). When you callva_start



, you need to pass it a format string (or more generally, the last parameter not changing for the function).

For example, this acts like printf

, but prints to both stdout

, and another file of your choice:

void tee(FILE *f, char const *fmt, ...) { 
    va_list ap;
    va_start(ap, fmt);
    vprintf(fmt, ap);
    va_end(ap);
    va_start(ap, fmt);
    vfprintf(f, fmt, ap);
    va_end(ap);
}

      

It uses vprintf

and vfprintf

, therefore, it does not (directly) use va_arg

itself, onlyva_start



and va_end

, but this is enough to show how the fmt

use ofva_start



...

At one time it was actually unnecessary. When C was shiny and new, you might have a function equivalent to: int f(...);

.

However, during the first attempt at standardizing C, this was eliminated in favor of the macros noted above (va_start



, va_arg

, va_end

), Which requires at least one named parameter. Older macros put a number of requirements in the calling convention:
  • Parameters are always passed in the same way, regardless of type or number.
  • It is always easy to find the first argument that was passed.

With the usual C conditional call (all arguments are passed on the stack, arguments are moved from right to left), this was correct. You basically just looked at the top of the stack, navigated back to the return address, and there was the first argument.

With other calling conventions, things were not so simple. For example, just pushing arguments from left to right means that the first argument (format string, in case printf

) is like an arbitrary distance down the stack with an arbitrary number of other arguments after it.

What they ran into was to pass directly the previous (named) argument va_start



(and va_start is the macro that usually uses the address of that argument). If you push from right to left, this will give you the address, regardless of the distance the stack needs, then va_arg

can go back to the stack to get other variables.

This was apparently seen as an acceptable compromise, especially since functions that take variable arguments almost always take at least one named parameter.

+7


source


Because he doesn't want to guess what to print



+4


source


Required as it is printf

used to print data. Imagine what happens if you don't print anything. Nothing. So why remove this setting?

Same thing in scanf

: do you need to read the data somehow and how are you going to do it if you don't know the format of that data?

Some functions have no parameters because they don't need them, for example

void Hello(void) { puts("Hello"); }

      

Thus, they can survive without parameters. About printf

:

int printf(void) { //imaginary function, don't use it!
    // WTF? What to print?
    // Absolutely nothing! What the purpose then?
    return smth;
}

      

Then this one printf

is completely useless if no arguments are passed .

+1


source


In general, functions with an unknown number of arguments rely on va_start

, va_arg

and va_end

to handle arguments that are not explicitly listed in the function's parameter list.

va_start

needs the last named parameter to work. Therefore, a function that has an unknown number of arguments must have at least one named argument.

For printf

option / argument defining the format specification is the best choice as the required option / argument.

+1


source


Without a description of the format, printf did not understand what to print. For C, everything is just bytes, so printf has no idea what data is being passed to it, and therefore has no idea how to represent it.

When you're new to C, you still don't know how true this is, especially if you've learned a language in which print () understands the type of data it sees.

0


source







All Articles