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);
}
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);
}
}
I'm creating my own kind of C library with my own kind of functions and also to help be better understand C and not just depend on GNU C Library for everything.
So far I got a bit of functions running but I wan't to tweak my printo function a little bit to support unlimited arguments (Restricted to chars only but your answer may also support passing in integer arguments). Here is the printo code:
#include "../GV.h"
#include "OtherUtils.h"
int print(char *WRITEOUT1){
char *WRITEOUT=&WRITEOUT1[0];
int AMOUNT=GetCharSize(WRITEOUT1);
register int SYSCALLNO asm("rax")=SYSWRITE;
register int FD asm("rdi")=STANDARDFD;
register char *BUF asm("rsi")=WRITEOUT;
register int BYTES asm("rdx")=AMOUNT;
asm("syscall");
return 0;
}
GetCharSize function code if anyone needs it:
#include "../GV.h"
int GetCharSize(char *arg){
for(i=0;arg[i]!='\0';i++){
}
return i;
}
GV.h has variables defined like int i;
Before I asked this question I looked into C pre-processors like __VA_ARGS__ but I somewhat couldn't wrap my head around it.
The ... notation is a part of the syntax of the C language. It is used in defining the argument list of a function as the last argument and means "followed by zero or more arguments of any type". E.g.
int printf (char *format, ...);
A function defined in this way can now be called with all the mandatory arguments, plus any number of additional arguments, like printf.
A function defined is this way must have a means of knowing how many arguments there are, and what the type of each argument is. printf knows this from the format specification string, the only required argument of printf.
Assuming an Intel system that uses a stack to pass arguments, and where arguments are pushed right-to-left (last argument pushed first), so the first optional argument will be directly after the format specification string on the stack, printf now proceeds as follows: take the address of the format specfication string and increment that address with the size of a char *. This is the start of the optional arguments. Now look at the format specifier string to know the type of the next argument; get that type of argument from the stack, increment it with the size of that argument to get the next address. Do this until there are no more format specifiers.
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.
I know it's a basic question ,
How can I build\write a function that can receive 3 or 4 arguments ?
Or more general , How can i write a function that can receive unknown number of arguments ?
Thanks !
To define a function with an unknown number of arguments the first one must be known. Then you have to include the stdarg.h library to access the arguments using it's functions: va_start, va_args, va_en and the type va_list.
In general the function is defined this way. Note that the first argument is not always of type int. It can be const char * for more controle on your arguments. for exemple in the printf() function.
type myFunction(int n, ...)
{
int i;
va_list args;
va_start(args, n);
for (i=0; i<n; i++){
// your argument is va_arg(args, int);
//... do something with your aruments
}
va_end(args);
// return your value
}
check these resources for more about stdarg.h http://www.cplusplus.com/reference/cstdarg/
or http://en.wikipedia.org/wiki/Stdarg.h
You need a function with a variadic parameter list. Use ellipses to define it:
void foo(int first, ...)
{
}
Use var_args to parse the parameters. The first parameter is usually used to
address the other parameters
control how the other parameters shall be treated
For the more general aspect, you can store the arguments in an array. And you can then pass a pointer of the array or the array itself to the actual function. This permits you to manipulate those arguments.
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.