16

I have two variadic function as foo(format, ...) and bar(format, ...). I want to implement function foo so that it can invoke bar with the same list of arguments it has. That is,

foo(format...)
{
 ...
 bar(format, ...);
}

For instance, invoking foo("(ii)", 1, 2) will invoke bar with same arguments bar("(ii)", 1, 2). How should this foo function be implemented?

PS: function bar is from a legacy library which I cant change its interface.

Richard
  • 14,642
  • 18
  • 56
  • 77
  • 1
    Duplicate of http://stackoverflow.com/questions/150543/forward-an-invocation-of-a-variadic-function-in-c – Adam Rosenfield Mar 21 '11 at 21:32
  • 2
    I don't know what you're trying to accomplish, but I'm almost willing to bet that you'll find the following standard library functions handy: `vprintf()`, `vfprintf()` and `vsprintf()`. – Emile Cormier Mar 21 '11 at 21:34
  • Does this answer your question? [Forward an invocation of a variadic function in C](https://stackoverflow.com/questions/150543/forward-an-invocation-of-a-variadic-function-in-c) – imz -- Ivan Zakharyaschev Apr 05 '23 at 16:46

4 Answers4

13

Can't be done, as long as all you have is a bunch if functions with ... arguments.

You have to plan ahead for things like that and implement each variadic fuinction in two-staged fashion

void vfoo(format, va_list *args) {
  /* Process `*args` */
}

void foo(format, ...) {
  va_list args;
  va_start(args, format);
  vfoo(format, &args);
  va_end(args);
}

Once you have each of your variadic functions implemented through a pair of va_list * function and ... function, you can delegate the calls using the va_list * versions of the functions

void vfoo(format, va_list *args) {
  ...
  vbar(format, args);
  ...
}
AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
10

GCC can construct function calls at runtime.

foo() {
   void *args = __builtin_apply_args();
   void *ret = __builtin_apply(bar, args, ???);
    __builtin_return(ret);
}

??? is the amount of stack space the arguments take up, which is not necessarily trivial to compute: you will need to understand what the arguments are and architecture-specific details on how they are passed.

Other GCC extensions allow further trickery with macros and inline functions.

ephemient
  • 198,619
  • 38
  • 280
  • 391
4

Short answer - you cannot. Make bar take a va_list. If you're willing to lock this down to one specific compiler, you could probably do it with inline assembly, but with standard C or C++ it's not possible.

You should, as a general rule, always implement your vararg functions in terms of va_list and then make a wrapper ellipsis function calling the real va_list function.

Erik
  • 88,732
  • 13
  • 198
  • 189
  • I somewhat disagree with the 'short answer.' It can be done in C++0x with variadic templates (see answer elsewhere). I'm only going of the question tags though -- the C++ one in particular :) – phooji Mar 21 '11 at 21:08
  • @Max Lybbert: Which one of those would C++0x be? – phooji Mar 21 '11 at 21:19
  • @phooji: c++0x isn't c++ (yet) - won't do answering a c++-tagged Q with c++0x :) – Erik Mar 21 '11 at 21:20
  • @Erik: Aw so little love for 0x! – phooji Mar 21 '11 at 21:23
  • 1
    @Erik: I know... but do you really want the committee to spend time on the name too? :-p – phooji Mar 21 '11 at 21:32
  • @phooji: my comment referred to the original answer, not your comment. As in "If you're willing to lock this down to one specific compiler, you could probably do it in inline assembly (or compiler specific extensions)." – Max Lybbert Mar 21 '11 at 23:22
  • 1
    @Max Lybbert: Ah. I was reading too much into your comment. Apologies. – phooji Mar 21 '11 at 23:24
  • I wrote my comment while you were writing yours. If I had seen your comment, I would have made it more clear that I was referring to the OP. – Max Lybbert Mar 22 '11 at 00:19
3

This works in C++:

#include <iostream>

template<typename Format>
void meheer(const Format& format) {
  std::cout << format << std::endl;;
}

template<typename Format, typename Elt, typename ... Args>
void meheer(const Format& format, const Elt & e, const Args&... args) {
  std::cout << format << e;
  meheer(format, args...);
}

template<typename Format, typename ... Args>
void ohai(const Format& format, const Args&... args) {
  meheer(format, args...);
}

int main(int argc, char ** argv) {
  ohai(1,2,3);

  return EXIT_SUCCESS;
}

Output:

12131

Of course, this is C++0x specific, but it works in my not-super-recent version of gcc. See also: http://en.wikipedia.org/wiki/C%2B%2B0x#Variadic_templates

Update Added full-length example.

phooji
  • 10,086
  • 2
  • 38
  • 45