我对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 draft(ISO/IEC 9899:2011)
对象ap可以作为参数传递给另一个函数;如果该函数使用参数ap调用va_arg宏,则调用函数中的ap值是不确定的,并且应该在进一步引用ap之前传递给va_end宏。
但后者添加
允许创建指向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使用方面存在(相同)问题的人的附加要点。
此致
答案 0 :(得分:3)
行为完全一致,因为尽管vtest
的论点被写为va_list ap
,ap
没有类型 va_list
但是而不是指针类型va_list
衰变到什么。这符合,因为标准允许va_list
为数组类型。此问题的解决方案是使用va_copy
将ap
复制到本地va_list
:
va_list ap2;
va_copy(ap2, ap);
// ...
vptest(count, &ap2);
// ...
va_end(ap2);
由于ap2
的定义和类型由您控制,&ap2
具有传递给vptest
的正确类型。