I have a problem with variable functions under Linux amd64 (x86_64).
My example builds and works fine on linux i386 (ia32), but when building for linux amd64, GCC produces the following errors:
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 **'
Here is an example:
#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; }
According to project C11 ( ISO / IEC 9899: 2011 )
The ap object can be passed as an argument to another function; if this function calls the va_arg macro with the ap parameter, the ap value in the calling function is undefined and must be passed to the va_end macro before any additional reference to ap.
But the latter adds
It is allowed to create a pointer to va_list and pass this pointer to another function, in which case the original function can additionally use the original list after returning another function.
It is not clear to me if here the AMD 64 ABI is incorrectly related to the standard.
Changing the vtest() function to use a pointer on the first call resolves the problem, but not so that something that does not work in internal functions actually works in an external function.
@@ -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);
If someone can find something, if AMD64 ABI will meet the standard. Extra points for people who provide me with other ABI (same) problems when using stdarg.
Hi