在v中使用va_list作为数组

问题描述 投票:1回答:3

像数组一样读取va_list而不是使用va_arg函数是安全且定义的行为吗?

EX:

void func(int string_count, ...)
{
    va_start(valist, string_count);
    printf("First argument: %d\n", *((int*)valist));
    printf("Second argument: %d\n", *(((int*)valist)+1));
    va_end(valist);
}

分配EX的问题相同:

void func(int string_count, ...)
{
    va_start(valist, string_count);
    printf("Third argument: %d\n", *(((int*)valist)+2));
    *((int*)valist+2)=33;
    printf("New third argument: %d\n", *(((int*)valist)+2));
    va_end(valist);
}

PS:这似乎适用于GCC

c arrays pointers variadic-functions undefined-behavior
3个回答
3
投票

不,它不是,你不能假设任何东西,因为不同的库实现各不相同。访问值的唯一可移植方法是使用stdarg.h中定义的宏来访问省略号。类型的大小很重要,否则你最终会读取车库,如果你读取的字节多于传递的字节数,那么你就有了未定义的行为。

所以,要获得一个值,你必须使用va_arg

见:STDARG documentation

你不能继续猜测va_list是如何工作的,或者是关于特定的实现。 va_list如何工作取决于ABI,架构,编译器等。如果你想更深入地了解va_list,请参阅this answer

编辑

几个小时前,我写了this answer解释如何使用va_*宏。看看那个。


3
投票

不,这不安全且定义明确。 va_list结构可以是任何东西(你假设它是指向第一个参数的指针),并且参数可以或可以不在被指向的某个存储区中的“正确顺序”中连续存储。

Example of va_list implementation that doesn't work for your code - 在这个设置中,一些参数在寄存器而不是堆栈中传递,但va_arg仍然必须找到它们。


0
投票

如果实现的文档指定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的编译器可能会查看test的定义,注意它(显然)在第一个参数为零时忽略它的可变参数,从而得出结论它不需要计算并传递someComplicatedComputation的结果。即使平台的文档记录了可变参数的布局,编译器无法看到它们被访问的事实也可能导致它得出结论它们不是。

© www.soinside.com 2019 - 2024. All rights reserved.