Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

varargs(va_list va_start) doesn't work with pass-by-reference parameter [duplicate]

Possible Duplicate:
Are there gotchas using varargs with reference parameters

Hi, I have a problem with varargs. Look at my code(Microsoft Visual Studio 2005 or 2008).

#include <stdarg.h>

struct Test { int a; };

void T1(int n, ...) {
 va_list args;
 va_start(args, n);
 char* p = va_arg(args, char*);
 va_end(args);
}

void T2(Test n, ...) {
 va_list args;
 va_start(args, n);
 char* p = va_arg(args, char*);
 va_end(args);
}

void T3(const Test& n, ...) {
 va_list args;
 va_start(args, n);
 char* p = va_arg(args, char*);  // p corrupt!!
 va_end(args);
}

int _tmain(int argc, _TCHAR* argv[]) {
 const Test t;
 T1(1, "Test1");
 T2(t, "Test2");
 T3(t, "Test3");
 return 0;
}

function T1, T2 work well. But T3 function have a problem. The pointer p doesn't point "Test3". Can't I use va_start with pass-by-reference? Thanks in advance.

like image 657
P-P Avatar asked Jul 06 '10 07:07

P-P


2 Answers

You cannot use references with va_start according to C++ Standard 18.7/3:

The restrictions that ISO C places on the second parameter to the va_start() macro in header are different in this International Standard. The parameter parmN is the identifier of the rightmost parameter in the variable parameter list of the function definition (the one just before the ...). If the parameter parmN is declared with a function, array, or reference type, or with a type that is not compatible with the type that results when passing an argument for which there is no parameter, the behavior is undefined.

like image 197
Kirill V. Lyadvinsky Avatar answered Oct 14 '22 22:10

Kirill V. Lyadvinsky


Short answer: no, you cannot do that.

NOTE: I saw the first answer which quotes the standard but I believe it is worth showing also my tests.

va_start is defined like this:

Visual 6: #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )

Visual 8: #define _crt_va_start(ap,v) ( __va_start(&ap, _ADDRESSOF(v), _SLOTSIZEOF(v), \ __alignof(v), _ADDRESSOF(v)) )

With this code:

#include <cstdio>

int main()
{
    char c;
    char &rc = c;
    int i;
    int &ri = i;

    printf("char ref:%d\n", sizeof(rc));
    printf("int ref:%d\n", sizeof(ri));

    return 0;
}

output

char ref:1
int ref:4

Since at implementation level references are passed on stack in a similar way to pointers this represents a problem since the size differs (it is because of the macro which computes the size of the type not taking into account that the parameter is actually a reference, which is not constant but depends on actual size of the type).

like image 41
INS Avatar answered Oct 14 '22 21:10

INS