Подтвердить что ты не робот

Varargs (va_list va_start) не работает с параметром pass-by-reference

Возможный дубликат:
Есть ли gotchas, использующие varargs со ссылочными параметрами

Привет, у меня проблема с varargs. Посмотрите мой код (Microsoft Visual Studio 2005 или 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;
}

функция T1, T2 работает хорошо. Но функция T3 имеет проблему. Указатель p не указывает "Test3". Не могу ли я использовать va_start с пошаговой ссылкой? Спасибо заранее.

4b9b3361

Ответ 1

Вы не можете использовать ссылки с va_start в соответствии с С++ Standard 18.7/3:

Ограничения, которые ISO C помещает во второй параметр в макрос va_start() в заголовке  в этом международном стандарте отличаются. Параметр parmN является идентификатором самый правый параметр в списке переменных параметров определения функции (тот, который был непосредственно перед...). Если параметр parmN объявлен с помощью функции, массива или ссылочного типа или с типом, который несовместим с типом, который возникает при передаче аргумента, для которого нет параметра, поведение undefined.

Ответ 2

Короткий ответ: нет, вы не можете этого сделать.

ПРИМЕЧАНИЕ. Я увидел первый ответ, который цитирует стандарт, но я считаю, что стоит также показать мои тесты.

va_start определяется следующим образом:

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

С помощью этого кода:

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

Выход

char ref:1
int ref:4

Так как на уровне реализации ссылки передаются в стеке аналогично указателям, это представляет проблему, поскольку размер отличается (это из-за макроса, который вычисляет размер типа, не принимая во внимание, что этот параметр фактически является ссылка, которая не является постоянной, но зависит от фактического размера типа).