Проблема с передачей ссылки в качестве именованного параметра в функцию с переменным числом аргументов

У меня проблемы в Visual Studio 2003 со следующим:

void foo(const char*& str, ...) {
    va_list args;
    va_start(args, str);

    const char* foo;
    while((foo = va_arg(args, const char*)) != NULL) {
        printf("%s\n", foo);
    }
}

Когда я называю это:

const char* one = "one";
foo(one, "two", "three", NULL);

Я получил:

Местоположение чтения нарушения доступа 0xcccccccc

в строке printf() -- va_arg() вернул 0xcccccccc. Наконец-то я обнаружил, что первый параметр — это ссылка, которая его ломает — если я сделаю его обычным char*, все будет в порядке. Кажется, не имеет значения, какой это тип; будучи ссылкой приводит к сбою во время выполнения. Это известная проблема с VS2003, или это каким-то образом является законным? В GCC этого не происходит; Я не тестировал более новые Visual Studio, чтобы увидеть, исчезнет ли поведение.


person Michael Mrozek    schedule 17.05.2010    source источник


Ответы (1)


VS2005 тоже вылетает на нем.

Проблема в том, что va_start использует адрес переданного ей аргумента, а поскольку str является ссылкой, ее адрес является адресом переменной "one", определенной в вызывающем объекте, а не адресом в стеке.

Я не вижу способа получить адрес переменной стека (аргумент, который фактически содержит адрес "одного", который передается), но есть некоторые обходные пути:

  • Вместо "const char * &str" используйте "const char *str" или "const char **str"
  • Добавьте следующий аргумент также в список «фиксированных» аргументов.

Этот код иллюстрирует второй вариант:

void foo(const char* &str, const char *arg1, ...) {
    if (arg1) {
       va_list args;
       va_start(args, arg1);
       printf ("%s\n", arg1);
       const char* foo;
       while((foo = va_arg(args, const char*)) != NULL) {
           printf("%s\n", foo);
       }
    }
}
person Patrick    schedule 18.05.2010
comment
О, это действительно очевидно в ретроспективе; Я предполагаю, что реализация glibc va_start не зависит от адреса последнего именованного аргумента, она вычисляет начало ... каким-то другим способом - person Michael Mrozek; 18.05.2010
comment
Только что найдено на velocityreviews.com/forums/t281115-va_start-and-references. .html, что использование va_start для ссылки не разрешено. Также см. stackoverflow. com/questions/222195/. - person Patrick; 18.05.2010
comment
Просто искал ссылку va_arg C++, и вуаля. - person Patrick; 18.05.2010