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

6

6

Why doesn't C allow a function with variable length argument list such as:

void f(...)
{
    // do something...
}
Mcgovern answered 4/7, 2011 at 10:49 Comment(1)
Pre-standard C allowed such functions.Sollie
C
10

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.

Christan answered 4/7, 2011 at 11:7 Comment(2)
Unix <varargs.h> (a predecessor and inspirer for the standard facility) allowed only variable arguments. The C rationale states that the possibility of having fixed types arguments before the varargs is an innovation of the standardization process. I'll also note that C++ allows having no fixed type argument, and that the only use I've seen for it was in template meta-programming contexts.Kellen
I think "...so the callee has to know the type of the first vararg anyway in order to read it." is the key insight here.Humectant
S
9

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.

Syncopation answered 4/7, 2011 at 10:52 Comment(5)
+1 for being the only answer by someone who actually read the question and explained why it wasn't allowed.Hienhieracosphinx
@WTP: strictly speaking, "...for being the first answer by someone who actually read [...], and made that clear"Taper
imo "because it's syntax" is not an explanation, just a statement of a fact.Metope
Consider the Münchhausen trilemma.Overflight
@Aleks: All of your answer is information only, it's the definition of var arg list usage in C, not an answer to my question. C++ supports void f(...); without a problem!Mcgovern
Y
1

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.

Yenyenisei answered 4/7, 2011 at 10:51 Comment(1)
And va_start needs a function parameter name.Insolate
R
1

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.

Refine answered 2/10, 2014 at 3:30 Comment(0)
M
0

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.

Metope answered 4/7, 2011 at 11:27 Comment(0)
P
-2

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);
Platform answered 4/7, 2011 at 11:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.