最近在花时间研读C++。

函数这章讲到了函数的变长参数(ellipsis...),但是primer中讲得比较浅,提到了怎么声明怎么调用,但是没有写明在函数内部是如何获取变长的参数的。

1)省略号(ellipsis)

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

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

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

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

2)通用的工作原理

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

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

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

3)如何获取变长参数

现在,我们要关注的是函数内部的实现细节。当我看到primer这部分的时候还真是好奇实现细节呢,只怪我孤陋寡闻,以前没见过⊙﹏⊙b。

为了解决变长参数问题,需要用到以下几个宏(以下定义来自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'。为简单起见,没有做任何异常处理,理解这些宏的使用方法即可。

 1 #include <iostream> 2 #include <stdarg.h> 3 using namespace std; 4  5 void myprintf(const char *format...) 6 { 7     va_list argptr; 8     va_start(argptr, format);        //va_start 9       10     char ch;11     while (ch = *(format++))        //逐个遍历format字符串12     {13         if (ch == '%')14         {15             ch = *(format++);16             if (ch == 's')17             {18                 char *name = va_arg(argptr, char *);    //va_arg19                 cout<<name;20             }21             else if (ch == 'd')22             {23                 int age = va_arg(argptr, int);    //va_arg24                 cout<<age;25             }26         }27         else28         {29                 cout<<ch;30         }31     }32     cout<<endl;33     va_end(argptr);        //va_end34 }35 36 int main()37 {38     myprintf("My name is %s, age %d.", "AnnieKim", 24);39     return 0;40 }

代码写得较粗糙,表介意。变长参数问题也就先到这里。

(完)

原创文章,欢迎转载,转载请注明出处:http://www.cnblogs.com/AnnieKim。

转载于:https://www.cnblogs.com/AnnieKim/archive/2011/11/25/ellipsis.html

如何获取函数的变长参数(va_list, va_start, va_arg, va_end)相关推荐

  1. 变长参数va_list va_start va_arg va_end

    对于int printf(const char *format, ...);这种变长参数,需要使用va_list va_start va_end va_arg来访问参数. 下面是一个tutorials ...

  2. va_list/va_start/va_arg/va_end深入分析

    va_list/va_start/va_arg/va_end这几个宏,都是用于函数的可变参数的. 我们来看看在vs2008中,它们是怎么定义的: 1: ///stdarg.h 2: #define v ...

  3. 可变参数:va_list(),va_start(),va_arg(),va_end() 详细解析

    目录 1.含义: 2.使用: 3.连续打印出自定义格式的文字: 1.含义: (1)va_list是C语言中的一个宏定义,用于表示一个变长参数列表.它是一个指向变长参数列表的指针,可以通过宏va_sta ...

  4. Va_list Va_start va_arg Va_end 的用法

    首先我们先看看它的头文件是怎么描述的 stdarg.h #pragma once#ifndef _INC_STDARG #define _INC_STDARG#if !defined(_WIN32) ...

  5. C语言使用函数参数传递中的省略号:va_list, va_start, va_arg, va_end

    首先要处理这种省略号的参数的话,需要包含头文件#include <stdarg.h>,然后利用下面的函数对"..."省略号变量进行处理. va_list arg; ty ...

  6. Spark UDF变长参数的二三事儿

    在复杂业务逻辑中,我们经常会用到Spark的UDF,当一个UDF需要传入多列的内容并进行处理时,UDF的传参该怎么做呢? 下面通过变长参数引出,逐一介绍三种可行方法以及一些不可行的尝试... 引子 变 ...

  7. C++11新特性之变长参数模板详解

    本文主要介绍了C++11变长参数模板,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 目录 C++11 变长参数模板 变长函数参数 ...

  8. c语言 宏 变长参数,科学网—C/C++中处理变长参数函数(Variadic Function)的几个宏 - 彭彬的博文...

    近日在模式中进行非线性方程组求解时遇到变长参数函数的问题,以前从来没有自己写过变长参数的函数,于是补了一下课,将近日对该小问题的学习和理解整理如下. 一.变长参数函数(variadic functio ...

  9. matlab 变长参数,变长参数函数的概念

    分享一个2015年华为笔试知识点:变长参数函数 变长参数的函数即参数个数可变.参数类型不定 的函数. 设计一个参数个数可变.参数类型不定的函数是可能的,最常见的例子是printf函数.scanf函数和 ...

最新文章

  1. java线程暂停_Java之线程停止
  2. win10+tensorflow import cv2 bug解决
  3. 8086标志操作指令
  4. [html] 如何在不同的端口间共享cookie?
  5. Hadoop Balancer运行速度优化
  6. linux防火墙能阻止cc攻击吗,linux csf 防火墙 防止少量的ddos cc攻击很有效
  7. 自己做的一个水印生成类
  8. win8.1安装马上6,连不上
  9. thinkserver TS250安装centos7.5经验
  10. 机器人操作系统、自动驾驶等研发工具整理
  11. 基于java餐饮管理系统的设计与实现(开题报告+审批表+任务书+项目源码+外文中献+中期检查表).rar
  12. sweetalert加载弹窗定时自动关闭
  13. [渝粤教育] 西南科技大学 仓储与配送管理 在线考试复习资料
  14. 如何清理系统大量的残余文件和系统垃圾文件?(win10)
  15. 如何利用蜜蜂剪辑切割音频文件
  16. Terminator的快捷键操作
  17. 操作系统——磁盘操作
  18. 阿里云函数计算(fc)使用体验
  19. ⚡豆瓣告诉你《扫黑风暴》如何【短评爬取+词云】 ⚡
  20. 中国健身、俱乐部和健身房管理软件系统行业市场供需与战略研究报告

热门文章

  1. 安装Docker环境并下载TensorFlow镜像
  2. IBM TPM2.0 模拟器
  3. JavaWeb——swagger使用
  4. windows下安装mongodb4.x版本
  5. PHP中include和require的区别详解
  6. 与Xcode相比Adobe AIR开发iOS的优势和局限
  7. 14个非常棒的 JavaScript 游戏开发框架推荐
  8. android:id=@android:id/list,Logcat错误 - 内容必须有一个ListView的id属性是'android.R.id.list'...
  9. 【java学习之路】(java SE篇)007.常用类
  10. SQL中 NVL()函数的使用