| PRB: Using References with va_* Macros from stdarg.hLast reviewed: July 31, 1997Article ID: Q119394 | 
| The information in this article applies to: 
 
 SYMPTOMSIn Microsoft C++, if you use functions that accept a variable number of arguments, you may encounter problems when trying to use the va_* family of functions to access the parameters if the second parameter used for the va_start macro is a reference type. 
 CAUSEThis problem is caused by the way that the va_start macro is defined and the way that the C++ language handles taking the address of a reference. Applying the "address of" operator to a reference type results in a pointer to the object that is being referred to. The va_start macro takes the address of the last named parameter to locate subsequent parameters. When the last named parameter is a reference, this causes problems because the macro is no longer referring to the current call stack but whatever follows the object being referred to, which could be a previous call stack or a global memory object. 
 RESOLUTIONThe workaround is to redefine the va_start macro to use inline assembly to subvert the C++ language. NOTE: This solution is not portable and will require changing if you intend your source code to be used on non-Intel platforms. 
 MORE INFORMATIONThe va_start macro is used in conjunction with the va_arg macro to "walk" the stack to get the parameters passed to the variable argument list. The va_start macro is defined as follows: 
 #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )where va_list is defined as a char * on Intel platforms. The macro parameter "ap" is of type va_list. The problem arises from taking the address of the second parameter, "v", if v is a reference type. The net result of this macro being expanded is that ap is supposed to point to the first of the variable parameters. Casting v to a non-reference type intuitively seems like the logical solution, but because the result of a cast is not an l-value, the compiler returns an error message. NOTE: The only way to get an l-value from a cast is to cast the value to a reference type, which results in the same problem. 
 Sample CodeThe sample code below demonstrates a solution for this problem:
    /* Compile options needed:  none
   */
   #include <stdio.h>
   #include <stdarg.h>
   // Uncomment the following lines to work-around the problem:
   //
   // #ifdef va_start
   // #undef va_start
   //
   // #ifdef _WIN32
   // #define va_start(ap,v) {int var= _INTSIZEOF(v); \
   //                __asm lea eax,v __asm add eax,var __asm mov ap,eax \
   //                }
   // #else
   // #define va_start(ap,v) { int var=_INTSIZEOF(v);\
   //                __asm lea ax,v __asm add ax,var __asm mov ap,ax\
   //                }
   // #endif
   // #endif
   void numprint( int &first ... )
   {
     va_list ap;
     va_start( ap, first );
     printf("%d\n", first );
     int ival = va_arg( ap, int );
     printf("%d\n", ival );
     double dval = va_arg( ap, double );
     printf( "%.2f\n", dval );
     va_end(ap);
   }
   void main()
   {
     int i=100,j=1000;
     float f=999.99;
     numprint( i,j,f );
   }
 | 
| Additional query words: ellipsis 
 © 1998 Microsoft Corporation. All rights reserved. Terms of Use. |