繁体   English   中英

c函数如何接收可变长度参数?

[英]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_startap指向第二个参数,

va_argap移至下一个参数,

va_endap指向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_listva_startva_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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM