[英]c how does function receive variable length argument?
如果我有一个函数接收可变长度参数
void print_arg_addr (int n, ...)
我可以使用这三个宏来解析参数
va_start(ap,v)
va_arg(ap,t)
va_end(ap)
以我的理解
va_start让ap指向第二个参数,
va_arg将ap移至下一个参数,
va_end让ap指向NULL。
因此,我使用下面的代码段来检查我的理解,但事实证明ap不会改变,我希望ap每次都会增加4。
void print_arg_addr (int n, ...)
{
int i;
int val;
va_list vl;
va_start(vl,n);
for (i=0;i<n;i++)
{
val=va_arg(vl,int);
printf ("ap:%p , %d\n",vl,val);
}
va_end(vl);
printf ("ap:%p \n",vl);
}
int main()
{
print_arg_addr(5,1,2,3,4,5);
}
输出:
ap:0x7ffc62fb9890 , 1
ap:0x7ffc62fb9890 , 2
ap:0x7ffc62fb9890 , 3
ap:0x7ffc62fb9890 , 4
ap:0x7ffc62fb9890 , 5
ap:0x7ffc62fb9890
谢谢!
va_list
(例如vl
)是某种抽象数据类型 ,不允许将其传递给printf
。 它的实现是您的编译器(和处理器体系结构 )专用的,并且与ABI和调用约定有关 。 使用所有警告和调试信息编译代码: gcc -Wall -Wextra -g
。 您会收到警告,并且行为不确定,因此您应该非常害怕 。
换句话说,将va_list
, va_start
, va_end
(以及所有stdarg(3) ...)视为编译器提供的某种魔术 。 这就是为什么它们是C11规范的一部分(读取为n1570 ),并且通常以编译器内置的形式实现的原因。
如果您需要了解va_list
和friends的内部知识 (但您不需va_list
),请深入研究编译器(并研究ABI )。 由于GCC是数百万个源代码行的免费软件 ,因此您可能需要花费很多年对其进行研究。 就您而言,我认为不值得付出努力。
您还可以使用gcc -O -S -fverbose-asm
查看生成的汇编代码( .s
文件)
当前的调用约定使用处理器寄存器。 这就是为什么了解可变参数调用的细节很复杂的原因。 在1980年代,参数被压入计算机堆栈,那时va_start
返回了一些指向堆栈的指针。 现在事情变得更加复杂,您不想陷入这种复杂性。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.