Why variadic functions require at least two arguments? - c

I'm trying to plug a hole in my knowledge. Why variadic functions require at least two arguments? Mostly from C's main function having argc as argument count and then argv as array of arrays of chars? Also Objective-C's Cocoa has NSString methods that require format as first argument and afterwards an array of arguments ([NSString stringWithFormat:#"%#", foo]). Why is it impossible to create a variadic function accepting only a list of arguments?

argc/argv stuff is not really variadic.
Variadic functions (such as printf()) use arguments put on the stack, and don't require at least 2 arguments, but 1.
You have void foo(char const * fmt, ...) and usually fmt gives a clue about the number of arguments.
That's minimum 1 argument (fmt).

C has very limited reflection abilities so you must have some way to indicate what it is that the variable arguments contain - either specifying the number of arguments or the type of them (or both), and that is the logic behind having one more parameter. It is required by the ISO C standard so you can't omit it. If feel you don't need any extra parameters because the number and type of the arguments is always constant then there is no need for variable arguments in the first place.
You could of course design other ways to encode the number / type information inside the variable arguments such as a sentinel value. If you want to do this, you can just supply a dummy value for the first argument and not use it in the method body.
And just to be pedantic about your title, variadic functions only require one argument (not two). It's perfectly valid to make a call to a variadic function without providing any optional arguments:
printf("Hello world");

I think, that the reason is the following:
in the macro va_start(list, param); you specify the last fixed argument - it is needed to determine the address of the beginning of the variable arguments list on the stack.

How would you then know if the user provided any arguments?
There has to be some information to indicate this, and C in general wasn't designed to do behind-your-back data manipulation. So anything you need, it makes you pass explicitly.

I'm sure if you really wanted to you could try to enforce some scheme whereby the variadic function takes only a certain type of parameter (a list of ints for example) - and then you fill some global variable indicating how many ints you had passed.
Your two examples are not variadic functions. They are functions with two arguments, but they also highlight a similar issue. How can you know the size of a C array without additional information? You can either pass the size of the array, or you describe a scheme with some sentinel value demarcating the end of the array (i.e. '\0' for a C string).
In both the variadic case and the array case you have the same problem, how can you know how much data you have legitimate access to? If you don't know this with the array case, you will go out of bounds. If you don't know this with the variadic case you will call va_arg too many times, or with the wrong type.
To turn the question around, how would you be able to implement a function taking a variable number of arguments without passing the extra information?

Related

No way for a C user-defined function to find out the total number of arguments passed to it? [duplicate]

This question already has answers here:
How to count the number of arguments passed to a function that accepts a variable number of arguments?
(13 answers)
Closed 1 year ago.
This web page says:
C supports variable numbers of arguments.
Okay, I got that.
But there is no language provided way for finding out total number of arguments passed.
Really? Is that true?
Apparently it is true because in every example that I have seen of a function with a variable number of arguments, there is always an argument that specifies the number of arguments, e.g.,
int sum(int numargs, ...)
Isn't that cheating?
Isn't the whole point of a function with a variable number of arguments is for the function to figure out how many arguments are provided? (Not be told how many arguments are provided)
Is there no way to create a function that sums an arbitrary number of integers, without the caller telling the function how many integers there are? (And without forcing the caller to append some sort of sentinel value like NULL onto the end of their argument list)
Is this possible:
int sum(...)
To really understand why this is true, and why there can only be workarounds like providing sentinel value or format string (like printf does), you need to look at how C functions are compiled.
https://en.wikipedia.org/wiki/X86_calling_conventions
If you look at the assembly that is generated (try gcc -S if you are on a *nix type OS), you will see there is no information regarding how many arguments are being passed, and it is up to the code of the function to pull them off the stack (usually, some conventions pass some arguments via registers).
As a matter of fact, not only the count, but the type information is lost in compilation as well.
Unlike other, newer languages, all C function has to access parameters is a stack pointer, from there it is up to the function to decide what to pop off the stack and how to interpret it.
The variadic syntax in C just allows you to bypass the rigid argument checks during compilation, and give back some of the assembly level freedom regarding function arguments.

How does Stack Activation Frame for Variable arguments functions works?

I am reading http://www.cs.utexas.edu/users/lavender/courses/cs345/lectures/CS345-Lecture-07.pdf to try to understand how does Stack Activation Frame for Variable arguments functions works?
Specifically how can the called function knows how many arguments are being passed?
The slide said:
The va_start procedure computes the fp+offset value following the argument
past the last known argument (e.g., const char format). The rest of the arguments are then computed by calling
va_arg, where the ‘ap’ argument to va_arg is some fp+offset value.*
My question is what is fp (frame point)? how does va_start computes the 'fp+offset' values?
and how does va_arg get 'some fp+offset values? and what does va_end supposed to do with stack?
The function doesn't know how many arguments are passed. At least not in any way that matters, i.e. in C you cannot query for the number of arguments.
That's why all varargs functions must either:
Use a non-varying argument that contains information about the number and types of all variable arguments, like printf() does; or
Use a sentinel value on the end of the variable argument list. I'm not aware of a function in the standard library that does this, but see for instance GTK+'s gtk_list_store_set() function.
Both mechanisms are risky; if your printf() format string doesn't match the arguments, you're going to get undefined behavior. If there was a way for printf() to know the number of passed arguments, it would of course protect against this, but there isn't. So it can't.
The va_start() macro takes as an argument the last non-varying argument, so it can somehow (this is compiler internals, there's no single correct or standard answer, all we can do from this side of the interface is reason from the available data) use that to know where the first varying argument is located on the stack.
The va_arg() macro gets the type as an "argument", which makes it possible to use that to compute the offset, and probably increment some state in the va_list object to point at the next varying argument.

Relaying optional arguments in a wrapper for a variadic function

I've just discovered variadic functions in C and have defined one as a general notification typedef, that as well as a pointer to a text string can optionally have whatever arguments sent along with it- useful as a generic debug function for instance where I want all the output string manipulation in one place.
Since I want my C files to be as generic as possible I have static variables that contain pointers to possible callbacks in higher code, populated in an init call. Since the pointers may be null if higher code isn't interested, I'd normally have a local wrapper that only calls through the pointer if it's not null. But I'm having trouble figuring out how to forward this fuzzy thing represented by '...' and simply calling the function with '...' in the argument list gives a syntax error.
Is there any way to do this, or am I stuck with having a dummy local handler and having init set null callbacks to a pointer to that?
You can't pass on the variadic arguments. You have to fetch them into a va_list and pass this to the inner function.
Take a look at this Question at the C FAQ. It defines a variadic error function that wants to forward to printf. This is just your use case.
In the same FAQs, it is generally recommended to have a version taking va_list for every (or most) variadic functions

Why is void f(...) not allowed in C?

Why doesn't C allow a function with variable length argument list such as:
void f(...)
{
// do something...
}
I think the motivation for the requirement that varargs functions must have a named parameter is for uniformity of va_start. For ease of implementation, va_start takes the name of the last named parameter. With a typical varargs calling convention, and depending on the direction arguments are stored, va_arg will find the first vararg at address (&parameter_name) + 1 or (first_vararg_type*)(&parameter_name) - 1, plus or minus some padding to ensure alignment.
I don't think there's any particular reason why the language couldn't support varargs functions with no named parameters. There would have to be an alternative form of va_start for use in such functions, that would have to get the first vararg directly from the stack pointer (or to be pedantic the frame pointer, which is in effect the value that the stack pointer had on function entry, since the code in the function might well have moved the sp since function entry). That's possible in principle -- any implementation should have access to the stack[*] somehow, at some level -- but it might be annoying for some implementers. Once you know the varargs calling convention you can generally implement the va_ macros without any other implementation-specific knowledge, and this would require also knowing how to get at the call arguments directly. I have implemented those varargs macros before, in an emulation layer, and it would have annoyed me.
Also, there's not a lot of practical use for a varargs function with no named parameters. There's no language feature for a varargs function to determine the type and number of variable arguments, so the callee has to know the type of the first vararg anyway in order to read it. So you might as well make it a named parameter with a type. In printf and friends the value of the first parameter tells the function what the types are of the varargs, and how many of them there are.
I suppose that in theory the callee could look at some global to figure out how to read the first argument (and whether there even is one), but that's pretty nasty. I would certainly not go out of my way to support that, and adding a new version of va_start with extra implementation burden is going out of my way.
[*] or if the implementation doesn't use a stack, to whatever it uses instead to pass function arguments.
With variable-length argument list you must declare the type of the first argument - that's the syntax of the language.
void f(int k, ...)
{
/* do something */
}
will work just fine. You then have to use va_list, va_start, va_end, etc. inside the function to access individual arguments.
C does allow for variable length arguments, but you need to use va_list, va_start, va_end, etc. for it. How do you think printf and friends are implemented? That said, I would recommend against it. You can usually accomplish a similar thing more cleanly using an array or struct for the parameters.
Playing around with it, made this nice implementation that I think some people might want to consider.
template<typename T>
void print(T first, ...)
{
va_list vl;
va_start(vl, first);
T temp = first;
do
{
cout << temp << endl;
}
while (temp = va_arg(vl, T));
va_end(vl);
}
It ensures you have one variable minimum, but allows you to put them all in a loop in a clean way.
There's no an intrisic reason why C can't accept void f(...). It could, but "designers" of this C feature decided not to do so.
My speculation about their motivations is that allowing void f(...) would require more "hidden" code (that can be accounted as a runtime) than not allowing it: in order to make distinguishable the case f() from f(arg) (and the others), C should provide a way to count how many args are given, and this needs more generated code (and likely a new keyword or a special variable like say "nargs" to retrieve the count), and C usually tries to be as minimalist as possible.
The ... allows for no arguments, ie: for int printf(const char *format, ...); the statement
printf("foobar\n");
is valid.
If you don't mandate at least 1 parameter (which should be used to check for more parameters), there is no way for the function to "know" how it was called.
All these statements would be valid
f();
f(1, 2, 3, 4, 5);
f("foobar\n");
f(qsort);

Mapping variable argument LISP function to C function - C

I am developing a custom LISP interpreter. It won't support defining functions like in LISP, instead all functions are mapped to C functions. When it sees an expression like,
(substr 'input '1 '1)
it knows to call internal substr function and return the result.
Now I am planning to implement a message function which supports basic formatting and writes the output to stdout. Something like,
(message "Hello, %s" name)
%s will be replaced with value in variable name.
Current plan is to directly pass the format and arguments to functions like printf. In that way, I can support all formats that printf supports. But problem comes with variable number of arguments. One way to do will be something like,
if(argcount == 1)
/* call printf with one arg */
else if(argcount == 2)
/* call printf with two arg */
....
This works, but I am wondering is there a better way to achieve this?
I doubt there is a way to do this. The reason is that the number of parameters to your lisp function is only known at runtime, but the number of arguments to a C function must be known at compile time.
This includes va_lists unless you want to hack at them in some kind of platform specific way.
The best you can really do is write a function in C which is capable of looping through the arguments one at a time and doing something with them. The only way I can see around this is to not only store a function pointer for each of your internal functions, but to also store a "calling convention" which will give information about whether it takes parameters in the ordinary way or whether it finishes with the equivalent of a va_list.
Functions like printf would have a wrapper, printf_wrapper, say, and you'd store a function pointer to the wrapper. This wrapper would accept the format string as an ordinary parameter, followed by a list or array of other parameters (roughly analogous to a va_list).
You might indicate that printf_wrapper finishes with a parameter that expects a list by specifying the calling conventions for the printf_wrapper function as "va_list_type", meaning that it takes the usual fixed parameters, and that all remaining parameters must be bundled up and supplied to it as a list.
Of course writing a printf_wrapper function which can split up and parse a format string into multiple format strings is a bit of work. Here's an example of where I did precisely this so that I could add my own custom format specifiers:
https://github.com/wbhart/bsdnt/blob/v0.26/helper.c
Have your C function take parameters somewhat like argc/argv. That is, take a parameter specifying the number of parameters, and then a pointer to a list of pointers for each parameter.
Slightly better than an if-else chain would be a switch.
switch(argcount){
case 1: printf(arg[0]); break;
case 2: printf(arg[0],arg[1]); break;
//etc.
}

Resources