Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C: variable argument list using stdarg.h

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.

like image 551
Hamza Avatar asked Mar 23 '26 04:03

Hamza


2 Answers

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.

like image 87
AnT Avatar answered Mar 24 '26 19:03

AnT


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."

like image 26
Jon Watte Avatar answered Mar 24 '26 18:03

Jon Watte