Меня беспокоят вариативные функции под Linux amd64 (x86_64).
В моем примере сборка и работа на linux i386 (ia32) работает нормально, но при сборке для linux amd64 GCC выдает такие ошибки:
stdarg.c: In function ‘vtest’:
stdarg.c:21:5: attention : passing argument 2 of ‘vptest’ from incompatible pointer type [enabled by default]
stdarg.c:5:1: note: expected ‘struct __va_list_tag (*)[1]’ but argument is of type ‘struct __va_list_tag **’
Вот пример:
#include <stdio.h>
#include <stdarg.h>
static int
vptest(int count, va_list *a)
{
printf("%8s: a = %p\n", __func__, a);
printf("%8s: %d: %d\n", __func__, count, va_arg(*a, int));
return 0;
}
static int
vtest(int count, va_list ap)
{
printf("%8s: &ap = %p\n", __func__, &ap);
/* passing a pointer to ap allows ap to be used again in the calling function */
for(; count > 1; count --) {
vptest(count, &ap);
}
if (count) {
printf("%8s: %d: %d\n", __func__, count, va_arg(ap, int));
}
return 0;
}
static
int test(int count, ...)
{
va_list ap;
va_start(ap, count);
printf("%8s: &ap = %p\n", __func__, &ap);
/* after passing ap to subfunction, this function must not use ap again without calling va_start */
vtest(count, ap);
va_end(ap);
return 0;
}
int
main(void)
{
test(4,
1, 2, 3, 4);
return 0;
}
Согласно черновику C11 (ISO / IEC 9899: 2011)
Объект ap может быть передан в качестве аргумента другой функции; если эта функция вызывает макрос va_arg с параметром ap, значение ap в вызывающей функции является неопределенным и должно быть передано в макрос va_end до любой дальнейшей ссылки на ap.
Но последние добавляют
Разрешается создать указатель на va_list и передать этот указатель другой функции, и в этом случае исходная функция может в дальнейшем использовать исходный список после возврата из другой функции.
Мне не ясно, является ли AMD 64 ABI неправильно здесь считается стандартом.
Изменение функции vtest()
на использование указателя при первом вызове устраняет проблему, но кажется неправильным, если что-то не работает во внутренних функциях, на самом деле работает во внешней функции.
@@ -12,16 +12,16 @@
}
static int
-vtest(int count, va_list ap)
+vtest(int count, va_list *a)
{
- printf("%8s: &ap = %p\n", __func__, &ap);
+ printf("%8s: a = %p\n", __func__, a);
/* passing a pointer to ap allows ap to be used again in the calling function */
for(; count > 1; count --) {
- vptest(count, &ap);
+ vptest(count, a);
}
if (count) {
- printf("%8s: %d: %d\n", __func__, count, va_arg(ap, int));
+ printf("%8s: %d: %d\n", __func__, count, va_arg(*a, int));
}
return 0;
@@ -37,7 +37,7 @@
printf("%8s: &ap = %p\n", __func__, &ap);
/* after passing ap to subfunction, this function must not use ap again without calling va_start */
- vtest(count, ap);
+ vtest(count, &ap);
va_end(ap);
Если бы кто-то мог где-то найти, соответствует ли поведение AMD64 ABI стандарту. Дополнительные баллы для людей, которые предоставляют мне другие ABI с (той же) проблемой при использовании stdarg.
С Уважением