像数组那样读取va_list而不是使用va_arg函数是安全且定义的行为吗?
ex:
void func(int string_count, ...)
{
va_start(valist, string_count);
printf("First argument: %dn", *((int*)valist));
printf("Second argument: %dn", *(((int*)valist)+1));
va_end(valist);
}
分配的同样问题例如:
void func(int string_count, ...)
{
va_start(valist, string_count);
printf("Third argument: %dn", *(((int*)valist)+2));
*((int*)valist+2)=33;
printf("New third argument: %dn", *(((int*)valist)+2));
va_end(valist);
}
ps:这似乎在GCC
否,不是,您不能假设任何事情,因为实现各不相同。访问值的唯一便携方式是使用stdarg.h
中定义的宏来访问省略。该类型的大小很重要,否则您最终会阅读车库而且,如果您的阅读字节多于通过的字节,则您的行为不确定。
因此,要获得一个值,您必须使用va_arg
。
请参阅:stdarg文档
您无法猜测va_list
的工作原理或特定的猜测执行。va_list
的工作方式取决于ABI,体系结构,编译器等。如果您想要更深入的va_list
视图,请参阅这个答案。
编辑
几个小时前,我写了这个答案,解释了如何使用 va_*
-MACROS。看看那个。
不,这不是安全且定义明确的。va_list
结构可以是任何东西(您认为它是第一个参数的指针(,并且参数可能会或可能不会连续存储在"正确的顺序"中。
va_list实现的示例不适合您的代码 - 在此设置中,某些参数在寄存器而不是堆栈中传递,但是va_arg
仍然必须找到它们。
如果实现的文档指定可以以超出标准中给出的方式使用va_list,则可以在该实现中以这种方式使用它们。即使在指定参数布局的平台上,尝试以其他方式使用参数也可能产生不可预测的后果。例如,在一个平台上以相反的顺序在堆栈上推动杂货参数,如果要做以下操作:
int test(int x, ...)
{
if (!x)
return *(int*)(4+(uintptr_t)&x); // Address of first argument after x
... some other code using va_list.
}
int test2(void)
{
return test(0, someComplicatedComputation);
}
正在处理test2的编译器可能会查看测试的定义,请注意,它(显然(忽略了它的变异论证参数为零,因此得出的结论是,它不需要计算和传递躯体发行的结果。即使文档对于平台记录了variadic参数的布局,这一事实是编译器看不到他们被访问的可能会导致它得出结论他们不是。