1
votes

I have two functions and I'm trying call in the first function that require "(enum types type, ...)" to the second that also require "(enum types type, ...)" passing the "va_list args" of the first function to the second, see:

#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>

enum types {
  String, Integer, Double, Float = Double,
  End
};

void fn1(enum types type, va_list args);
void fn2(enum types type, ...);

int main() {
  fn1(Integer, 3);
  return 0;
}

void fn1(enum types type, va_list args) {
  va_list argsCopy;
  va_copy(argsCopy, args);
  fn2(type, &argsCopy);
  va_end(argsCopy);
}

void fn2(enum types type, ...) {
  va_list args;
  int count;
  va_start(args, type);
  count = 0;
  while (type != End) {
    switch (type) {
    case String:
      fprintf(stdout, "char arg[%d]: %s\n", count, va_arg(args, const char *));
      break;
    case Integer:
      fprintf(stdout, "int arg[%d]: %d\n", count, va_arg(args, int));
      break;
    case Double:
      fprintf(stdout, "double arg[%d]: %f\n", count, va_arg(args, double));
      break;
    default:
      fprintf(stderr, "unknown type specifier\n");
      break;
    }
    type = va_arg(args, enum types);
    count++;
    }
  va_end(args);
}

I got:

Segmentation fault

So I tried with this macro:

#ifdef HAVE_VA_LIST_AS_ARRAY
#define MAKE_POINTER_FROM_VA_LIST_ARG(arg) ((va_list *)(arg))
#else
#define MAKE_POINTER_FROM_VA_LIST_ARG(arg) (&(arg))
#endif

//...

void fn1(enum types type, va_list args) {
  fn2(type, MAKE_POINTER_FROM_VA_LIST_ARG(args));
}

//...

and I got:

int arg[0]: 571263040
unknown type specifier
unknown type specifier
char arg[3]: UHåAWAVAUATSHì(L%X¸

So, What the way to do this? Is it possible?

1
You're doing it totally wrong. va_start is used in a function that ends with .... And is passed to a function that takes va_list.Antti Haapala
You also never use a value of End so your loop will try to access arguments that don't exist.Emanuel P
Just avoid variadic functions. It's a dangerous and superfluous feature, which mainly serves as a source of bugs.Lundin

1 Answers

2
votes

You seem to misunderstand vararg functions.

The fn2 function should invoke va_start, and then call fn1 with the va_list.

And your code should then call fn2 instead. And you must remember to add the End enumeration at the end of the argument list.

So your code should be:

fn2(Integer, 123, End);

And then fn2 should be something like:

void fn2(enum types type, ...)
{
    va_list args;
    va_start(args, type);
    fn1(type, args);
    va_end(args);
}

And finally put your loop and printing in the fn1 function:

void fn1(enum types type, va_list args)
{
    while (type != End)
    {
        // ...
        type = va_arg(args, enum types);
    }
}