Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use va_list object in a nested way, especially on gcc x64 compiler

Tags:

linux

gcc

g++

glibc

Please look through my small C/C++ program.

// va_nest.c
#include <stdarg.h>
#include <stdio.h>

void nest2(const char *fmt, ...)
{
    va_list args2, args_dig;
    int *pi, i;

    va_start(args2, fmt);

    args_dig = va_arg(args2, va_list); 
        // !!! try to fetch the nested va_list object.
    pi = va_arg(args_dig, int*);
    i = va_arg(args_dig, int);

    printf("Inner: @%p , %d\n", pi, i);

    va_end(args2);
}

void nest1(const char *fmt, ...)
{
    va_list args1;
    va_start(args1, fmt);

    nest2(fmt, args1);

    va_end(args1);
}

int main()
{
    int var = 11;
    printf("Outer: @%p , %d\n", &var, var);
    nest1("abc", &var, var);
    return 0;
}

On openSUSE 13.1 x86, it outputs just want I expect(no matter using gcc or g++),

Outer: @0xbfa18d8c , 11
Inner: @0xbfa18d8c , 11

However, it FAILS with x86_64 compiler on openSUSE 13.1 x64 machine.

If I compile it with gcc, it compiles ok, but output is unexpected.

$ gcc -o vac va_nest.c

$ ./vac
Outer: @0x7fffb20f766c , 11
Inner: @0x1b01000000636261 , 4209411

If I compile it with g++, it even fails to compile.

$ g++ -o vacpp va_nest.c
va_nest.c: In function ‘void nest2(const char*, ...)’:
va_nest.c:12:11: error: invalid array assignment
  args_dig = va_arg(args2, va_list);
           ^

gcc and g++ version is 4.8.1

Can anybody help me with that? I hope to achieve the same result on x64 as in Linux x86 compiler.

like image 470
Jimm Chen Avatar asked Jan 29 '26 21:01

Jimm Chen


1 Answers

Don't try to be clever with va_list. Instead, use code like this:

nest2(fmt, args1);

(i.e. make sure that all functions use the same structure hidden behind va_list). Then you can define the second function like so:

void nest2(const char *fmt, va_list args1)

Also make sure that you call va_end() exactly once. Nesting won't work reliably (i.e. if it works, that's more luck than anything else).

If in doubt, look at the source code of GLIBC, especially fprintf.c and vfprintf.c.

int
__fprintf (FILE *stream, const char *format, ...)
{
  va_list arg;
  int done;

  va_start (arg, format);
  done = vfprintf (stream, format, arg);
  va_end (arg);

  return done;
}

and later:

int
vfprintf (FILE *s, const CHAR_T *format, va_list ap)
{
like image 193
Aaron Digulla Avatar answered Feb 01 '26 11:02

Aaron Digulla



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!