Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set a default value when no extra arguments are present using va_list in C

I've had problem when trying write a function which has a default value when no extra arguments are given. I've tried detecting if the only argument given is equal to NULL (as suggested in other answers) but it doesn't seem to be working for me.

The actual implementation of this function takes a struct and adds it to a linked list given in the second argument. If no second argument is given, I want it to add it to a default global linked list which has been previously defined.

Below is a simpler version using int type arguments, but the principle of what I want to do is the same:

/* appropriate headers... */

void test(int a, ... ) {

   int b;

   va_list args;
   va_start(args,a);

   b = va_arg(args,int);

   if (b == NULL) { // check if no argument is given and set default value
       b = 0; 
   } // if b != NULL then it should be set to the value of the argument
   va_end(args);

   printf("%d %d\n",a,b);
}

int main() {
   test(1);
   test(1,1);
   return 0;
}

However, this gives the output:

1 *random memory address*
1 1

The output I want should have the first line as

1 0

If I can't use this method then does anyone have any ideas how I can achieve what I want? Thanks in advance.

like image 654
Overlord_Dave Avatar asked Jan 13 '12 01:01

Overlord_Dave


2 Answers

There is no way to do what you want with just va_list.

You can use macros and __VA_ARGS__ to force a certain argument to show up last in your argument list as a "terminator." i.e.:

#define TEST(a, ...) Test(a, __VA_ARGS__, 0)

Note that I'm using Visual C++. Other compilers might implement __VA_ARGS__ slightly differently so you may need to tweak the implementation.

like image 77
StilesCrisis Avatar answered Nov 15 '22 00:11

StilesCrisis


Your function accepting variable arguments has to be able to tell somehow when it has reached the end of the variable arguments. This can be by parsing information from the fixed arguments (e.g. an argument which tells you how many variable arguments were passed, or a format string which tells you what arguments are supposed to follow), or it can be by an explicit sentinel value, such as a null pointer, at the end of the variable arguments.

You seem to be wanting a major miracle; I'm sorry, only minor miracles are available.

You can design your interfaces like this:

int test1(int x, struct list *list) { ...code to handle adding x to arbitrary list... }

int test0(int x) { return test1(x, &global_struct); }

You then call test0() when you want to use the default list, and test1() when you want specify a different list.

Note that test0() is so simple that it is a good candidate for C99 inline function definition.

If you were using C++ you could provide a function with a default argument or an overloaded function (two argument lists and implementations, as above, but the same name). Of course, even more than in C, the use of global variables is deprecated in C++.

like image 33
Jonathan Leffler Avatar answered Nov 15 '22 00:11

Jonathan Leffler