Вопрос "Передать va_list или указатель на va_list?" содержит ответ, который цитирует стандарт (переменные аргументы ISO/IEC 9899: 1999 - §7.15) <stdarg.h>
, сноска 212), так как явно сказано, что:
Разрешено создавать указатель на
va_list
и передавать этот указатель на другую функцию, и в этом случае исходная функция может дополнительно использовать исходный список после возвращения другой функции.
Я компилирую код, который можно проиллюстрировать следующим (реальный код очень значительно сложнее, а оригинальные функции выполняют гораздо больше работы, чем показано здесь).
vap.c
#include <stdarg.h>
#include <stdio.h>
static void test_ptr(const char *fmt, va_list *argp)
{
int x;
x = va_arg(*argp, int);
printf(fmt, x);
}
static void test_val(const char *fmt, va_list args)
{
test_ptr(fmt, &args);
}
static void test(const char *fmt, ...)
{
va_list args;
va_start(args, fmt); /* First use */
test_val(fmt, args);
va_end(args);
va_start(args, fmt); /* Second use */
test_ptr(fmt, &args);
va_end(args);
}
int main(void)
{
test("%d", 3);
return 0;
}
Сообщения об ошибках
Когда я его компилирую (на RHEL5 с GCC 4.1.2 или 4.5.1), я получаю следующие сообщения об ошибках. Обратите внимание на то, что более информативное сообщение об ошибке 4.5.1 - команда GCC должна быть поздравлена с улучшением!
$ gcc --version
gcc (GCC) 4.5.1
Copyright (C) 2010 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ /usr/bin/gcc --version
gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-44)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ gcc -c vap.c
vap.c: In function ‘test_val’:
vap.c:13:5: warning: passing argument 2 of ‘test_ptr’ from incompatible pointer type
vap.c:4:13: note: expected ‘struct __va_list_tag (*)[1]’ but argument is of type ‘struct __va_list_tag **’
$ /usr/bin/gcc -c vap.c
vap.c: In function ‘test_val’:
vap.c:13: warning: passing argument 2 of ‘test_ptr’ from incompatible pointer type
$
Я получаю те же сообщения на MacOS X Lion с GCC/LLVM 4.2.1 и с GCC 4.6.1:
$ /usr/bin/gcc --version
i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)
Copyright (C) 2007 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ gcc --version
gcc (GCC) 4.6.1
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$
Вопросы
-
Может ли кто-нибудь сформулировать, почему функция
test_val()
не может передатьva_list
, переданную как аргументtest_ptr()
, тогда как функцияtest()
(которая создалаva_list
) может? -
Правильно ли GCC жаловаться на косвенную передачу указателя в
test_val()
?
В обоих случаях я вижу ответ нечетко, но я не могу описать его лаконично. Я думаю, что код в test_val()
злоупотребляет va_list
, и хорошо, что код не будет компилироваться, но я хотел бы быть уверен, прежде чем я его исправлю.
Обновление 2012-03-30
На этой неделе я занялся проблемным кодом. Прежде чем вносить изменения, я пошел, чтобы найти, где используются бесполезные функции — и это не так! Итак, я решил проблему с ошибкой компиляции, удалив функции (4 внешне видимых, но неиспользуемых, плюс 2 статических, содержащих содержащийся в нем код проблемы). Это было намного проще, чем придумать, как бороться с беспорядком. (Это также объясняет, почему никогда не было доказательств проблемы времени выполнения, вызванной кодом.)