Имам притеснения относно различни функции под 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.
за разбирането