C语言变长参数实现

在C编译器通常提供了一系列处理可变参数的宏,实现就像printf()那样的变长参数,这样可以屏蔽不同的硬件平台造成的差异,增加程序的可移植性。这些宏包括va_start、 va_arg和va_end等, 这些宏都是在<stdarg.h>里定义的。

采用ANSI标准形式时,参数个数可变的函数的原型声明是:
type funcname(type para1, type para2, ...)
这种形式至少需要一个普通的形式参数,后面的省略号不表示省略,而是函数原型的一部分。type是函数返回值和形式参数的类型。

不同的编译器,对这个可变长参数的实现不一样 ,gcc4.x中是采用内置函数的方法来实现。

接下来我们看看以下示例代码:

#include <stdarg.h>
#include <stdio.h>

int Sum (int, ...);

int main(void)
{
   int num;
   num = Sum(5, 1, 2, 3, 4);
   printf("%d/n", num);
   return 0;
}

int Sum (int n, ...)
{
   int i = 0, j = 0;
   va_list p;                       /*定义一个变量 ,保存函数参数列表的指针*/

   va_start(p, n);               /*用va_start宏初始化变量p,
                                         va_start宏的第2个参数n,
                                         是一个固定的参数,
                                         必须是我们自己定义的变长函数的最后一个入栈的参数
                                         也就是调用的时候参数列表里的第1个参数*/
  
   for (j = 1; j < n; ++j)        /* j从1开始,遍历所有可变参数 */
   {
        i += va_arg(p, int);   /*va_arg取出当前的参数,
                                            并认为取出的参数是一个整数(int) */
   }

   return i;
}

当我们调用Sum函数时,传递给Sum函数的参数列表的第一个参数n的值是5,
va_start 初始化 p使其指向第一个未命名的参数(n是有名字的参数) ,也就是1(第一个),
每次对 va_arg的调用,都将返回一个参数,并且把 p 指向下一个参数,
va_arg 用一个类型名来决定返回的参数是何种类型,以及在 var_arg的内部实现中决定移动多大的距离才到达下一个参数。

 

 

 

 

 void   test   (int   a,   ...)  
  {  
  char   *ap;  
  char   ch;  
  char   str[4];  
                short   s;  
                int   n;  
   
                ap   =   (char*)&a   ;  
                ap   +=   4;  
                ch   =   *ap;  
                ap   +=   4;  
                memcpy(str,   (char*)(*(unsigned   *)ap),   4);  
                ap   +=   4;  
                s   =   *((short   *)ap);  
                ap   +=   4;  
                n   =   *((int   *)ap);  
                ap   +=   4;  
                printf("a:   %d,   ch:   %c,   str:   %s,   s:   %d,   n:   %d/n",   a,   ch,   str,   s,   n);  
  }  
  int   main()  
  {  
                test(100,   'A',   "ABC",   123,   87654);  
                return   0;  
  }  
这个例子中参数们被放置在一个32位的数组中
参数int a是第一个参数,通过他的地址依次+32位即代码中的ap+=4就可以找到其他参数地址并转换成相应的类型

这种方式不灵活,不同的系统情况可能不同,所以最好用已经定义好的宏
type va_arg( va_list arg_ptr, type );
void va_end( va_list arg_ptr );
void va_start( va_list arg_ptr );
void va_start( va_list arg_ptr, prev_param );

参与评论 您还未登录,请先 登录 后发表或查看评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

dehuaodin

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值