The definition of printf function in C Language is:
int printf(const char * _Format, ...);
The same is for scanf and a lot of similar functions where is managed a variable number of arguments.
Why is there a _Format mandatory parameter?
The format string is mandatory because the way C's variable argument macros work depends on at least one argument being present, and using it to find the others.
Specifically, to read the other variable arguments, you use va_start (then va_arg repeatedly, once for each variable argument you want to read). When you call va_start, you need to pass it the format string (or, more generally, the last non-varying parameter to 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);
}
This uses vprintf and vfprintf, so it doesn't (directly) use va_arg itself, only va_start and va_end, but that's enough to show how the fmt is involved in using va_start.
At one time, this wasn't actually needed. Back when C was shiny and new, you could have a function equivalent to: int f(...);.
During the first C standardization effort, however, this was eliminated in favor of the macros noted above (va_start, va_arg, va_end) that require at least one named parameter. The older macros placed a number of requirements on the calling convention:
Parameters are always passed the same way, regardless of type or number.
It's always easy to find the first argument that was passed.
With the conventional C calling convention (all arguments are passed on the stack, arguments are pushed from right to left) this was true. You basically just looked at the top of the stack, moved backward past the return address, and there was the first argument.
With other calling conventions, things weren't so simple though. For example, just pushing arguments from left to right means that the first argument (the format string, in the case of printf) is buried some arbitrary distance down the stack, with an arbitrary number of other arguments after it.
The way they came up with to deal with that was to pass the immediately previous (named) argument to va_start (and va_start is a macro that will normally use the address of that argument). If you push from right to left, that will give you an address whatever distance needed down the stack, then va_arg can walk back up the stack to retrieve the other variable arguments.
This was apparently seen as an acceptable compromise, especially since functions that take variable arguments almost always take at least one named parameter anyway.
Because it doesn't want to guess what to print
It's mandatory because printf is used to print data. Imagine what'll happen if you print nothing. Nothing. So, why to remove that parameter?
That's the same thing about scanf: you need to read data somehow and how are you going to do it if you don't know the format of this data?
Some functions don't have parameters because they don't need them, eg
void Hello(void) { puts("Hello"); }
So, they can 'survive' without parameters. About printf:
int printf(void) { //imaginary function, don't use it!
// WTF? What to print?
// Absolutely nothing! What's the purpose then?
return smth;
}
Then this printf is absolutely useless when no arguments are passed.
In general, functions that have an unknown number of arguments rely on va_start, va_arg, and va_end to process the arguments that are not explicitly in the function's parameter list.
va_start needs the last named parameter to work with. Hence, a function that has an unknown number of arguments must have at least one named argument.
For printf the parameter/argument that specifies the format specification is the best choice as the required parameter/argument.
Without a format description, printf wouldn't understand what to print. To C, everything is just bytes, so printf has no idea what kind of data is being passed to it, and therefore no idea how to represent it.
When you're new to C, you might not yet realize how true this is, especially if you've learned a language where print() understands the type of data it's seeing.
Related
I want to create a function in C with variable length arguments in which I may not want to pass any variable at some point. I such a thing possible in C? I would like some code snippets if possible. Also, I have to mention that the function will have passed only char* variables when there are passed some variables.
A function with variable arguments must have at least one names argument in order to read the others.
For your particular case, since you want to pass a list of char * arguments you can use NULL to denote the end of the argument list. So in the case where there is nothing to pass, you just pass a singe NULL argument.
This is not supported by standard C.
For a function parameter type list terminated with an ellipsis, there must be at least one named parameter.
For a function defined with an identifier list, the number of arguments in the call must match the number of parameters in the definition; varying numbers of arguments are not supported.
If you will call a function with a varying number of char * arguments, and that number may be zero, you could declare the function with a dummy first argument that is always passed but never used, as with:
void foo(int dummy,...);
Note that passing no arguments is a troublesome design. Normally, routines that accept varying numbers of arguments infer the number of arguments from one or more arguments. For example, the first argument might contain the number of remaining arguments, or it might be a format string (as with printf) from which the number and types of remaining arguments can be deduced. If you want a function to accept zero arguments in some situations, it has to have a way of knowing whether it was called with zero arguments or more. That would require information in some global state, which is typically a bad design.
no you cant
you need at least one known argument
void foo(int dummy, ...)
{
va_list ap;
C does not provide any mechanism to allow a called function to determine how many arguments were provided. The mechanism must be part of the calling interface.
For example, printf relies on the % format specifications, while execv requires the caller to place a null pointer as the last argument.
A varargs function can be called with no variable arguments, but the caller must not attempt to access any variable argument in that case. For example, the mode argument to the Posix open() function is only consulted in the case that a new file is created, so it need not be supplied if the flags argument doesn't contain the O_CREAT flag (or some other extension flag, such as O_TMPFILE in Linux, which requests file creation).
The variable-length part of the prototype must follow at least one fixed argument. So it is not possible fir a varargs function to be called with no arguments at all.
Can you have in C variable length arguments functions with cases when you don't want to pass any variable?
Yes. In modern C, Code cannot define a ... function with no arguments, yet you can call such a function with no arguments by declaring the a function without function signature. In that way the function can be called with zero arguments.
The function still needs some way to understand the count of arguments. This is often done with the first argument as a count (or format) or a final argument as a sentinel.
Given "will have passed only char*"...
int foo_count(int counter, ...);
// zero usage example
foo_count(0);
int foo_sentinel(char *s);
// zero usage example
foo_sentinel((char*) NULL);
To do so with passing no arguments, the count needs to be conveyed in some other fashion, perhaps with a global variable - although this is not recommended. (Better to simply pass the count.)
Declare function:
int foo_count;
int foo(); // no prototype
Call function
foo_count = 0; foo()
foo_count = 1; foo("one")
foo_count = 2; foo("one", "two")
Define the function
int foo(char *s1, ...) {
if (foo_count > 0) {
va_list ap;
va_start(ap, s1);
puts(s1);
for (int i=1; i < foo_count; i++) {
puts(va_arg(ap, char *));
}
va_end(ap);
}
}
Why do I have to take an int type variable in c var_args function? Like printf is a built-in function that does not require the length of arguments to be declared before entering various variables...
The C standard does not require a function with a variable parameter list to have any particular argument type.
However, it is up to the function to make appropriate invocations to va_arg. To do that, the function has to have some way of knowing what arguments have been passed. You may implement that requirement in any way you desire, including:
Use a format string that contains conversion specifiers that indicate the argument types, as printf does.
Pass any description of the numbers and types of each argument. Encode them all in one array, pass several arguments describing the rest, describe one argument, then have that argument, then describe the next argument, then have that argument, and so on.
Deduce the arguments from the operation the function is requested to perform. For example, an open call might take flags that indicate whether it should create a file or just open an existing one. If it is to create a file, then it could take an additional parameter indicating the permissions to be set on the file, whereas, if it is merely opening an existing file, it would not take that parameter.
The answer has to do with compiler calling conventions. Here's a slightly simplified explanation:
Basically, when the compiler encounters a function call with N arguments, it generates code to push N arguments on the stack.
When the compiler compiles a function which takes N arguments, it generates code to pops N arguments off the stack.
There is no "secret" information telling the function how many arguments were pushed. For ordinary functions, the number and type of arguments agree only because the function prototype in the calling code agrees with the function definition.
For variadic functions, it's not possible to rely on the function definition. The ... literally means "we don't know what arguments will be pushed. So there needs to be an alternate source for the argument specification. A simple way to do it is just ensure the first argument is the count of fixed-size arguments to follow.
printf and family use a different method. The format string defines what type and how many arguments it will use.
C does not allow a variable argument function to optionally take zero parameters. That is, there must be a named parameter before the ....
For printf, the named parameter is the format string. When parsing the format string, the type of the next argument can be deduced, and the va_arg macro can be properly invoked.
If all the arguments are of the same type, you can use the named parameter to indicate the number of arguments being passed in. For example, if you are passing in a number of strings:
void foo_strings (int n, ...) {
va_list ap;
va_start(ap, n);
while (n--) {
const char *s = va_arg(ap, const char *);
foo(s);
}
va_end(ap);
}
However, you could have just as easily used a NULL to indicate there are no more strings. Then, the first argument could be used for something else, such as pointing to a function.
void foo_string (void (*foo)(const char *), ...) {
va_list ap;
va_start(ap, n);
const char *s = va_arg(ap, const char *);
while (s != NULL) {
foo(s);
s = va_arg(ap, const char *);
}
va_end(ap);
}
Is it safe and defined behaviour to read va_list like an array instead of using the va_arg function?
EX:
void func(int string_count, ...)
{
va_start(valist, string_count);
printf("First argument: %d\n", *((int*)valist));
printf("Second argument: %d\n", *(((int*)valist)+1));
va_end(valist);
}
Same question for assigningment
EX:
void func(int string_count, ...)
{
va_start(valist, string_count);
printf("Third argument: %d\n", *(((int*)valist)+2));
*((int*)valist+2)=33;
printf("New third argument: %d\n", *(((int*)valist)+2));
va_end(valist);
}
PS: This seems to work on GCC
No, it is not, you cannot assume anything because the implementation varies across libraries.
The only portable way to access the values is by using the macros defined in stdarg.h for accessing the
ellipsis. The size of the type is important, otherwise you end up reading garage
and if your read more bytes than has been passed, you have undefined behaviour.
So, to get a value, you have to use va_arg.
See: STDARG documentation
You cannot relay on a guess as to how va_list works, or on a particular
implementation. How va_list works depends on the ABI, the architecture, the
compiler, etc. If you want a more in-depth view of va_list, see
this answer.
edit
A couple of hours ago I wrote this answer explaining how to use the
va_*-macros. Take a look at that.
No, this is not safe and well-defined. The va_list structure could be anything (you assume it is a pointer to the first argument), and the arguments may or may not be stored contiguously in the "right order" in some memory area being pointed to.
Example of va_list implementation that doesn't work for your code - in this setup some arguments are passed in registers instead of the stack, but the va_arg still has to find them.
If an implementation's documentation specifies that va_list may be used in ways beyond those given in the Standard, you may use them in such fashion on that implementation. Attempting to use arguments in other ways may have unpredictable consequences even on platforms where the layout of parameters is specified. For example, on a platform where variadic arguments are pushed on the stack in reverse order, if one were to do something like:
int test(int x, ...)
{
if (!x)
return *(int*)(4+(uintptr_t)&x); // Address of first argument after x
... some other code using va_list.
}
int test2(void)
{
return test(0, someComplicatedComputation);
}
a compiler which is processing test2 might look at the definition of test,
notice that it (apparently) ignores its variadic arguments when the first
argument is zero, and thus conclude that it doesn't need to compute and
pass the result of someComplicatedComputation. Even if the documentation
for the platform documents the layout of variadic arguments, the fact that
the compiler can't see that they are accessed may cause it to conclude that
they are not.
As you can see from the code snippet below, I have declared one char variable and one int variable. When the code gets compiled, it must identify the data types of variables str and i.
Why do I need to tell again during scanning my variable that it's a string or integer variable by specifying %s or %d to scanf? Isn't the compiler mature enough to identify that when I declared my variables?
#include <stdio.h>
int main ()
{
char str [80];
int i;
printf ("Enter your family name: ");
scanf ("%s",str);
printf ("Enter your age: ");
scanf ("%d",&i);
return 0;
}
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(...);
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.
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.
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.
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)
Isn't the compiler matured enough to identify that when I declared my
variable?
No.
You're using a language specified decades ago. Don't expect modern design aesthetics from C, because it's not a modern language. Modern languages will tend to trade a small amount of efficiency in compilation, interpretation or execution for an improvement in usability or clarity. C hails from a time when computer processing time was expensive and in highly limited supply, and its design reflects this.
It's also why C and C++ remain the languages of choice when you really, really care about being fast, efficient or close to the metal.
scanf as prototype int scanf ( const char * format, ... ); says stores given data according to the parameter format into the locations pointed by the additional arguments.
It is not related with compiler, it is all about syntax defined for scanf.Parameter format is required to let scanf know about the size to reserve for data to be entered.
GCC (and possibly other C compilers) keep track of argument types, at least in some situations. But the language is not designed that way.
The printf function is an ordinary function which accepts variable arguments. Variable arguments require some kind of run-time-type identification scheme, but in the C language, values do not carry any run time type information. (Of course, C programmers can create run-time-typing schemes using structures or bit manipulation tricks, but these are not integrated into the language.)
When we develop a function like this:
void foo(int a, int b, ...);
we can pass "any" number of additional arguments after the second one, and it is up to us to determine how many there are and what are their types using some sort of protocol which is outside of the function passing mechanism.
For instance if we call this function like this:
foo(1, 2, 3.0);
foo(1, 2, "abc");
there is no way that the callee can distinguish the cases. There are just some bits in a parameter passing area, and we have no idea whether they represent a pointer to character data or a floating point number.
The possibilities for communicating this type of information are numerous. For example in POSIX, the exec family of functions use variable arguments which have all the same type, char *, and a null pointer is used to indicate the end of the list:
#include <stdarg.h>
void my_exec(char *progname, ...)
{
va_list variable_args;
va_start (variable_args, progname);
for (;;) {
char *arg = va_arg(variable_args, char *);
if (arg == 0)
break;
/* process arg */
}
va_end(variable_args);
/*...*/
}
If the caller forgets to pass a null pointer terminator, the behavior will be undefined because the function will keep invoking va_arg after it has consumed all of the arguments. Our my_exec function has to be called like this:
my_exec("foo", "bar", "xyzzy", (char *) 0);
The cast on the 0 is required because there is no context for it to be interpreted as a null pointer constant: the compiler has no idea that the intended type for that argument is a pointer type. Furthermore (void *) 0 isn't correct because it will simply be passed as the void * type and not char *, though the two are almost certainly compatible at the binary level so it will work in practice. A common mistake with that type of exec function is this:
my_exec("foo", "bar", "xyzzy", NULL);
where the compiler's NULL happens to be defined as 0 without any (void *) cast.
Another possible scheme is to require the caller to pass down a number which indicates how many arguments there are. Of course, that number could be incorrect.
In the case of printf, the format string describes the argument list. The function parses it and extracts the arguments accordingly.
As mentioned at the outset, some compilers, notably the GNU C Compiler, can parse format strings at compile time and perform static type checking against the number and types of arguments.
However, note that a format string can be other than a literal, and may be computed at run
time, which is impervious to such type checking schemes. Fictitious example:
char *fmt_string = message_lookup(current_language, message_code);
/* no type checking from gcc in this case: fmt_string could have
four conversion specifiers, or ones not matching the types of
arg1, arg2, arg3, without generating any diagnostic. */
snprintf(buffer, sizeof buffer, fmt_string, arg1, arg2, arg3);
It is because this is the only way to tell the functions (like printf scanf) that which type of value you are passing. for example-
int main()
{
int i=22;
printf("%c",i);
return 0;
}
this code will print character not integer 22. because you have told the printf function to treat the variable as char.
printf and scanf are I/O functions that are designed and defined in a way to receive a control string and a list of arguments.
The functions does not know the type of parameter passed to it , and Compiler also cant pass this information to it.
Because in the printf you're not specifying data type, you're specifying data format. This is an important distinction in any language, and it's doubly important in C.
When you scan in a string with with %s, you're not saying "parse a string input for my string variable." You can't say that in C because C doesn't have a string type. The closest thing C has to a string variable is a fixed-size character array that happens to contain a characters representing a string, with the end of string indicated by a null character. So what you're really saying is "here's an array to hold the string, I promise it's big enough for the string input I want you to parse."
Primitive? Of course. C was invented over 40 years ago, when a typical machine had at most 64K of RAM. In such an environment, conserving RAM had a higher priority than sophisticated string manipulation.
Still, the %s scanner persists in more advanced programming environments, where there are string data types. Because it's about scanning, not typing.
I have a function which accepts variable number of argumets of different data types using ellipsis. I wanted to know is there any way by which I can get each of them. If not all, atleast separate a particular argument (either first or last parameter) from the rest and va_list from the remaining.
Declaration goes like this :
int foo (char *a , ...)
Usage :
result = foo ("I'm a String",2,34.56,"one more String",2323232323);
result = foo ("I'm another String",3,"again one more String",34.62,111111111);
So, here(usage 1) I want to remove parameter '2' from the va_list got and make another va_list with the rest. Function declaration is flexible, and can be changed accordingly.
Thanks in advance
Note that variable argument functions must have a way to determine the types of the arguments in the ellipsis (va_list). The printf() and scanf() families of functions have the format string to specify the types; the open() system call has an optional third argument but it is always an int; and the execl() function takes a list of arguments all of the same type, char *, terminated by a NULL pointer).
If you have a function:
void foo_tail(va_list args);
You can write your function foo() as:
int foo(char *a, ...)
{
va_list args;
va_start(args, a);
int arg2 = va_arg(args, int);
foo_tail(args);
va_end(args);
return arg2;
}
This achieves what the question asks for:
remove parameter '2' from the va_list got and make another va_list with the rest.
Whether foo_tail() can work out what to do with the va_list it is given is a separate discussion; it is not clear how it would distinguish between the two calls shown in the question, but to handle both, that information would have to be made available somehow. A variable list of mixed types as shown is very problematic.
When you use va_arg the argument you get is actually removed from the va_list. So the rest of the arguments are already in your va_list.
However, you can not, say, get an arbitrary argument from the list. They have to be taken in order. You also must know the actual types of the arguments you're getting.