理解可变参数 va_list、va_start、va_arg、va_end 原理及使用方法

1、省略号(ellipsis)

在无法给出所有传递给函数的参数的类型和数目时,可以使用省略号(...)指定函数参数表。有如下几种形式:

void fun1(int a, double b, ...); //给出确定的几个参数,其他用省略号
void fun2(int a ...);            //省略号前有或者没有逗号都是可以的
void fun3(...);                  //也可以不确定任何参数,但和没有参数是不一样的

最典型的应用就是 printf 函数,printf 的声明和调用方法如下:

int printf( const char *format [,argument]... );    //官方声明
printf("My name is %s, age %d.", "AnnieKim", 24);   //调用

2、通用的工作原理

大多数带有变长参数的函数都利用显式声明的参数中的一些信息,来获取调用中提供的其他可选实参的类型和数目。

比如 printf 函数,就是根据第一个参数推导可选实参:如果第一个'%'后有一个's',说明后面要有第二个参数,类型是字符串;如果还有第二个'%',后面跟一个'd',说明还需要第三个参数,是一个整型等等。

所以说,通常情况下,第一个参数是必不可少的。

3、如何获取变长参数

为了解决变长参数问题,需要用到以下几个宏(以下定义来自 MSDN),并且使用这几个宏时必须至少提供一个显式的参数:

#include <stdarg.h>

type va_arg(
   va_list arg_ptr,
   type 
);
void va_end(
   va_list arg_ptr 
);
void va_start(
   va_list arg_ptr,
   prev_param 
);

其中,type 是指要获取的参数的类型,比如 int,char * 等,arg_ptr 是指向参数列表的指针(va_list类型),prev_param 是指最后一个显式声明的参数,以用来获取第一个变长参数的位置。

使用步骤:

a)定义一个 va_list 类型的变量,变量是指向参数的指针。

b)va_start 初始化刚定义的变量,第二个参数是最后一个显式声明的参数。

c)va_arg 返回变长参数的值,第二个参数是该变长参数的类型。

d)va_end 将 a) 定义的变量重置为 NULL,即:释放内存。

注意事项:

a)变长参数的类型和数目不能通过宏来获取,只能通过自己写程序控制。

b)编译器对变长参数函数的原型检查不够严格,会影响代码质量。

4、举个例子

最后举个例子,是自己写的 printf 函数,只能用于处理'%s'和'%d'。为简单起见,没有做任何异常处理,理解这些宏的使用方法即可。

#include <iostream>
#include <stdarg.h>
using namespace std;

void myprintf(const char *format...)
{
    va_list argptr;
    va_start(argptr, format); //va_start

    char ch;
    while (ch = *(format++)) //逐个遍历format字符串
    {
        if (ch == '%') {
            ch = *(format++);
            if (ch == 's') {
                char *name = va_arg(argptr, char *); //va_arg
                cout << name;
            } else if (ch == 'd') {
                int age = va_arg(argptr, int); //va_arg
                cout << age;
            }
        } else {
            cout << ch;
        }
    }
    cout << endl;
    va_end(argptr); //va_end
}

int main()
{
    myprintf("My name is %s, age %d.", "AnnieKim", 24);
    return 0;
}

转载:理解可变参数va_list、va_start、va_arg、va_end原理及使用方法 - 摩斯电码 - 博客园

(SAW:Game Over!)

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值