1

I was wondering if it's possible in C to create a variadic function that takes different types of arguments. i.e.

void fillDatabase(char* name, int age){
  writeToDatabase(name, age);
}

int main(){
  fillDatabase("Paul", 19);
  fillDatabase("Herbert");
}

Here I am trying to fill up a database with names and ages. But it's also possible to fill it up with only a name and no age. So I am wondering if I could use the same function for that or if I have to write two different ones?

Online I could only find examples for variadic functions with the same type of arguments.

Thanks in advance!

Tom
  • 2,545
  • 5
  • 31
  • 71
  • 3
    I think you're mixing up the concepts of variadic functions and function overloading. – Tim Čas Nov 16 '15 at 18:44
  • I added a link of what I found online – Tom Nov 16 '15 at 18:45
  • 5
    `printf` is a variadic function that can take different types of arguments... Note that you would need to provide some means of explicitly providing the argument types (which `printf`-like functions do via the format string). – jamesdlin Nov 16 '15 at 18:46
  • so hold on, what does that mean in regards to my example? – Tom Nov 16 '15 at 18:47
  • The variadic function has to know the argument types, in `printf` etc this is done with the format specifiers. – Weather Vane Nov 16 '15 at 18:48
  • It means that you should look at `printf` as an example. (BTW, the hoops that you have to jump through for variadic functions usually makes them not worth it.) – jamesdlin Nov 16 '15 at 18:48
  • You need to be able to tell which type each argument has, and how many arguments there are. – EOF Nov 16 '15 at 18:49
  • It could be done with each argument a `struct` or `union` specifying the data type and value, with a sentinel to end the sequence. – Weather Vane Nov 16 '15 at 18:50
  • 2
    Just *write two functions*. Writing a variadic function, using a `struct`, `union` or any other trick just asks for trouble. Seriously. – Karoly Horvath Nov 16 '15 at 18:50
  • 2
    Guys, if somebody asks you to help him shoot himself in the foot, you don't give him a gun... at the very least not without asking for a good reason... – Karoly Horvath Nov 16 '15 at 18:56
  • 1
    ok, thanks, I'll just use two functions – Tom Nov 16 '15 at 19:01
  • 1
    Just FYI, variadic functions should generally only be used when you *can't* know the number of variables at compile time or the number of variables is orthogonal. Otherwise, the benefits are... debatable. – Jason Nov 16 '15 at 19:15

2 Answers2

4

In C99, variadic functions use stdarg(3) operations (generally implemented as macros expanding to compiler-specific magical stuff, e.g. GCC builtins). The first arguments should have some fixed known type, and generally determinates how the other arguments are fetched; in several today's ABIs, variadic function argument passing don't use registers so is less efficient than fixed arity function calls.

In your case, you'll better have several functions. For inspiration sqlite has several open functions.

Notice that POSIX defines some function with one last optional argument, in particular open(2). This is probably implemented as having a function whose last argument can be not supplied.

You could read the ABI specification and the calling conventions specific to your implementation.

BTW, lack of function overloading (like in C++) can be understood as an advantage of C (the function name -which is the only thing the linker care about, at least on Linux & Unix- determines its signature). Hence C++ practically needs name mangling. Read also about dynamic linking and dlopen

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • 1
    Traditionally, no prototype for `open()` was supplied so programmers could call it with two or three arguments as needed. Nowadays, `open()` is declared as `int open(const char*, int, ...);` and uses variable arguments. – fuz Nov 16 '15 at 19:07
  • In practice, not really. – Basile Starynkevitch Nov 16 '15 at 19:09
  • So [POSIX](http://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html) is wrong in this regard? – fuz Nov 16 '15 at 19:12
  • No, I thought that *implementations* of `open` don't use `va_start`, but in musl-libc [open.c](http://git.musl-libc.org/cgit/musl/tree/src/fcntl/open.c) `va_start` is used. So I was wrong. IIRC, some old versions of Glibc didn't do that (but I might be wrong too) – Basile Starynkevitch Nov 16 '15 at 19:32
  • 1
    As I said, old implementations of `open()` just didn't supply a prototype and defined `open()` with a K&R-style definition and three arguments. The argument count mismatch is undefined behaviour, but works just fine on typical Unices as long as you never touch arguments that weren't supplied. – fuz Nov 16 '15 at 19:34
2

Check the man page for va_list, va_start, etc.

You declare your function prototype using the ... sequence to denote variable args:

void myfunction(FILE *, *fmt, ...);

For example, we declatre a struct of type va_list (assuming you included stdarg):

struct va_list l;

Initialise the list using the parameter BEFORE the ... - se we'd pass the *fmt pointer to va_start:

va_start(l, fmt);

Now, we can call va_arg to get a value...if we're processing a format string we might have a loop something like this:

while (*fmt) {
    /* Look for % format specifier... */
    if (*fmt == '%') {
        /* Following character can be c for char, i for int or f for float. */
        // Opps - advance to char following opening %...
        fmt++;

        if (*fmt == 'c')
            fprintf(stream, "%c", (char) va_arg(l, int));
        else if (*fmt == 'i')
            fprintf(stream, "%i", (int) va_arg(l, int));
        else if (*fmt == 'f')
            fprintf(stream, "%f", (float) va_arg(l, double));
        ... and so on...

You're relying on the character following the % to tell you what data type to expect in the corresponding parameter. Suggest you read the man pages for va_list.

Nunchy
  • 948
  • 5
  • 11
  • So how would you apply all this knowledge for the particular problem? – Karoly Horvath Nov 16 '15 at 22:35
  • Well...I don't really know the ins and outs of the particular problem I'm not the OP. Let the OP decide if my answer is adequate for his/her purposes, if it is then great...if not then sorry, keep looking. I don't really know what you want or expect me to tell you... – Nunchy Nov 16 '15 at 22:38