tags:

views:

84

answers:

2

Hi folks,

I am experimenting with variable argument lists and seeing some strange results...

The piece of code I am testing is:

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

void foo(int param1, int param2, ...)
{
    int param3 = 0;

    va_list ap;
    va_start(ap, param2);
    param3 = va_arg(ap, int);
    va_end(ap);

    printf("param3: %d\n", param3);
}


int main(void)
{
  foo(1,1);
  foo(1,1,42);

}

And the output for that snippet is:

param3: -1073748472
param3: 42

For the second call: 'foo(1,1,42)', everything seems to work as expected.

For the first call: 'foo(1,1)', the result look like an uninitialised int, although I do set it to 0 when I first initialise it at the beginning of the function.

I would like to be able to rely on the fact that the resultant variable should have the value 0 if the argument is not called. I would have thought va_arg() would be sensible enough to deal with that but it doesn't seem to be the case.

Any suggestions to deal with that?

Many thanks.

+6  A: 

The problem is that you're reading the value no matter whether it's passed or not. Thus, you're getting whatever junk happens to be on the stack at the offset where the argument was supposed to live.

When using varargs, you have to make sure that the initial arguments you pass make it clear what other arguments are present. printf() does this by counting % signs (although the programmer sometimes gets this wrong, and hilarity ensues)

The better answer is "don't use varargs; find some type-safe way of doing what you need."

Jon Watte
Or equivalently, "varargs is a nice hack exclusively for printf() and scanf()".
Artelius
Probbaly best to avoid it then, thanks for your answer.
Hamza
Not only printf(); the UNIX open() *system call* traditionally uses varargs as well for the file mode flags that only matter if O_CREAT is set.Also, there are great macro hacks that can be done using varargs, when you want to pass complex data structures as initialization data and whatnot.Luckily, C++ pretty much obsoletes any use of varargs :-)
Jon Watte
+8  A: 

Firstly, I don't see how the fact that you initialize param3 with zero should matter, since you overwrite that value later anyway.

Secondly, trying to "extract" a non-existing variadic argument produces undefined behavior. So, the only way to deal with that is not to attempt to extract the non-existing argument. There's no way to detect whether the argument exists or not. It is the caller's responsibility to inform the function how many variadic arguments it can safely extract.

AndreyT
You are right actually, my assumption was incorrect.Thanks for your comments.
Hamza