2010-07-06 15 views
12

Duplicar posible:
Are there gotchas using varargs with reference parametersvarargs (va_start va_list) no funciona con el parámetro pase por referencia

Hola, tengo un problema con varargs. Mira mi código (Microsoft Visual Studio 2005 o 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 funcionan bien. Pero la función T3 tiene un problema. El puntero p no señala "Test3". ¿No puedo usar va_start con pass-by-reference? Gracias de antemano.

+2

Exhibe el comportamiento previsto en g ++, pero eso realmente no significa mucho, ¿verdad? –

Respuesta

13

No puede utilizar referencias con va_start de acuerdo con C++ estándar 18.7/3:

Las restricciones que ISO C lugares en el segundo parámetro para la macro va_start() en la cabecera son diferentes en esta norma. El parámetro parmN es el identificador del parámetro más a la derecha en la lista de parámetros variables de la definición de la función (la que está justo antes de ...). Si el parámetro parmN se declara con una función, matriz o tipo de referencia, o con un tipo que no es compatible con el tipo que resulta al pasar un argumento para el que no hay parámetro, el comportamiento es undefined.

4

Respuesta corta: no, no puedes hacer eso.

NOTA: Vi la primera respuesta que cita el estándar pero creo que vale la pena mostrar también mis pruebas.

va_start se define así:

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)))

Con este código:

#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; 
} 

salida

char ref:1 
int ref:4 

Dado que en el nivel de implementación las referencias se pasan en la pila de manera similar a los punteros, esto representa un problema ya que el tamaño difiere (es debido a la macro que calcula el tamaño del tipo sin tener en cuenta que el parámetro es realmente referencia, que no es constante pero depende del tamaño real del tipo).

+1

Gracias. Es interesante. :) –

Cuestiones relacionadas