При попытке скомпилировать этот код
#include <stdarg.h>
void bar_ptr(int n, va_list *pvl) {
// do va_arg stuff here
}
void bar(int n, va_list vl) {
va_list *pvl = &vl; // error here
bar_ptr(n, pvl);
}
void foo(int n, ...) {
va_list vl;
va_list *pvl = &vl; // fine here
va_start(vl, n);
bar(n, vl);
va_end(vl);
}
int main() {
foo(3, 1, 2, 3);
return 0;
}
компилятор G CC выводит предупреждение о initialization from incompatible pointer type
в функции bar
. То же самое утверждение прекрасно в foo
.
. Кажется, что тип агента типа va_list
не является va_list
. Это легко проверить с помощью утверждения c типа
_Static_assert(sizeof(vl) == sizeof(va_list), "invalid type");
в функции bar
. С G CC _Static_assert
завершается неудачно. То же самое можно проверить и в C ++ с declytpe
и std::is_same
.
Я хотел бы взять адрес аргумента va_list vl
bar
и передать его в качестве аргумента bar_ptr
, do думает так, как описано в этой теме . С другой стороны, можно набрать bar_ptr(n, pvl)
напрямую из main
, заменив bar(n, vl)
.
В соответствии со сноской 253 C11 окончательного варианта ,
Разрешено создавать указатель на va_list
и передавать этот указатель другой функции
Почему этого нельзя сделать, если va_list
определен в качестве аргумента функции а не в теле функции?
Обходной путь:
Даже если это не отвечает на вопрос, возможный обходной путь - изменить содержимое bar
на используя локальную копию аргумента, созданного с помощью va_copy:
void bar(int n, va_list vl) {
va_list vl_copy;
va_copy(vl_copy, vl);
va_list *pvl = &vl_copy; // now fine here
bar_ptr(n, pvl);
va_end(va_copy);
}