1.带可变参数的函数由来

函数中的参数个数不确定时,这时候就需要带可变参数的函数!

如我们经常使用的C库函数printf()实际就是一个可变参数的函数,

其原型为:

 int   printf(   const   char*   format,   ...);

它除了有一个参数format固定以外,后面跟的参数的个数和类型是可变的。例如我们可以有以下不同的调用方法:

printf( "%d ",i);
printf( "%s ",s);
printf( "the number is %d ,string is:%s ", i, s);

2.带可变参数函数的实现,

原理:

  • 使用了指针参数来解决参数的可变问题,指针参数随着其移动指向不同的参数;
  • C语言的函数形参是从右向左压入堆栈的,以保证栈顶是第一个参数。

C语言标准库中头文件stdarg.h索引的接口包含了一组能够遍历变长参数列表的宏。

头文件

#include <stdarg.h>

几个宏

(1).  va_list  定义一个指针

用来定义一个表示参数表中各个参数变量,即定义了一个指向参数的指针, 用于指示可选的参数.

如:va_list ap;

(2). va_start(ap,v)  初始化指针

使参数列表指针ap指向函数参数列表中的第一个可选参数v是位于第一个可选参数之前的固定参数, 或者说最后一个固定参数.通常用于指定可变参数列表中参数的个数!

如有一va函数的声明是void va_test(char a, char b, char c, ...), 则它的固定参数依次是a,b,c, 最后一个固定参数v为c, 因此就是va_start(ap, c).


(3). va_arg(ap, type) 返回参数列表中指针ap所指的参数, 返回类型为type. 并使指针ap指向参数列表中下一个参数.返回的是可选参数, 不包括固定参数.

(4). va_end(ap) 清空参数列表, 并置参数指针arg_ptr无效.

例:

#include <iostream>
#include <stdarg.h>
using namespace std;
void simple_va_fun(int i,...); int main(int argc,char *argv[])
{
simple_va_fun();
simple_va_fun(,);
simple_va_fun(,,'a');
return ;
} void simple_va_fun(int i,...)
{
va_list arg_ptr; //定义可变参数指针
va_start(arg_ptr,i); // i为最后一个固定参数
int j=va_arg(arg_ptr,int); //返回第一个可变参数,类型为int
char c=va_arg(arg_ptr,char); //返回第二个可变参数,类型为char
va_end(arg_ptr); // 清空参数指针
printf( "%d %d %c\n",i,j,c);
return;
}
/*

输出为


100 4193388 ?
100 200 ?
100 200 a

*/

 

思路:

(1)首先在函数里定义一个va_list型的变量,这里是arg_ptr,这个变量是指向参数的指针.

(2)然后用va_start宏初始化变量arg_ptr,这个宏的第二个参数是第一个可变参数的前一个参数,是一个固定的参数.

(3)然后用va_arg返回第一个可变的参数,并赋值给整数j。va_arg的第二个参数是你要返回的参数的类型,这里是int型.  返回第一个可变参数后arg_ptr指向第二个可变参数,用同样的方法返回并赋值给c,类型为char类型。

(4)最后用va_end宏结束可变参数的获取。

小结:
可变参数的函数原理其实很简单,而va系列是以宏定义来定义的,实现跟堆栈相关.我们写一个可变函数的C函数时,有利也有弊,所以在不必要的场合,我们无需用到可变参数.如果在C++里,我们应该利用C++的多态性来实现可变参数的功能,尽量避免用C语言的方式来实现。

参考

http://www.jb51.net/article/41868.htm

C/C++中带可变参数的函数的更多相关文章

  1. 【c++】类中带默认参数的函数

    反思两个问题 1. 带默认参数的函数,为何声明.定义不能同时有参数? 2. 带默认参数的函数, 为何带默认参数的参数靠后站? 上程序 #include <iostream> #includ ...

  2. C函数和宏中的可变参数

    一:调用惯例 函数的调用方和被调用方对函数如何调用应该有统一的理解,否则函数就无法正确调用.比如foo(int n, int m),调用方如果认为压栈顺序是m,n,而foo认为压栈顺序是n, m,那么 ...

  3. C语言中可变参数的函数(三个点,“...”)

    C语言中可变参数的函数(三个点,“...”) 本文主要介绍va_start和va_end的使用及原理. 在以前的一篇帖子Format MessageBox 详解中曾使用到va_start和va_end ...

  4. [Effective JavaScript 笔记]第22条:使用arguments创建可变参数的函数

    第21条讲述使用可变参数的函数average.该函数可处理任意数量的参数并返回这些参数的平均值. 如何创建可变参数的函数 1.实现固定元数的函数 书上的版本 function averageOfArr ...

  5. C# 中的可变参数方法(VarArgs)

    首先需要明确一点:这里提到的可变参数方法,指的是具有 CallingConventions.VarArgs 调用约定的方法,而不是包含 params 参数的方法.可以通过MethodBase.Call ...

  6. PHP基础语法: echo,var_dump, 常用函数:随机数:拆分字符串:explode()、rand()、日期时间:time()、字符串转化为时间戳:strtotime()可变参数的函数:PHP里数组长度表示方法:count($attr[指数组]);字符串长度:strlen($a)

    PHP语言原理:先把代码显示在源代码中,再通过浏览器解析在网页上 a. 1.substr;  //用于输出字符串中,需要的某一部分 <?PHP $a="learn php"; ...

  7. 【转】C,C++中使用可变参数

    可变参数即表示参数个数可以变化,可多可少,也表示参数的类型也可以变化,可以是 int,double还可以是char*,类,结构体等等.可变参数是实现printf(),sprintf()等函数的关键之处 ...

  8. C语言利用va_list、va_start、va_end、va_arg宏定义可变参数的函数

    在定义可变参数的函数之前,先来理解一下函数参数的传递原理: 1.函数参数是以栈这种数据结构来存取的,在函数参数列表中,从右至左依次入栈. 2.参数的内存存放格式:参数的内存地址存放在内存的堆栈段中,在 ...

  9. c 可变参数 定义可变参数的函数

    定义可变参数的函数,需要在stdarg.h头文件中定义的va_list类型和va_start.va_arg.va_end三个宏. 定义可变参数函数 va_list ap;  //实际是定义一个指针va ...

随机推荐

  1. kbmMW 5.07.00试用笔记

    在kbmMW 5.06.20试用笔记中遇到的问题,在这个版本中,基本都解决了.但还是发现修正后存在的小问题及新问题: 1.Resolve返回值错误 当提交的ClientQuery是执行一条sql语句, ...

  2. Appium环境搭建过程中遇到的问题及解决办法

    一.[Error: Could not detect Mac OS X Version from sw_vers output: '10.12.6'] 解决办法: 1.vi /Applications ...

  3. API/SPI可扩展设计原则(转)

    API/SPI可扩展设计原则 博客分类: [设计体系]架构模式 API/SPISPISPI原则JAVA SPISPI机制  写本篇主要是用来后面写一篇可扩展性软件设计打好基础(苦于找不到一篇关于API ...

  4. RESTful Web Service 架构

    特点:简单,可靠,高效,跨平台和跨语言 含义: Web Service 简单来说是指提供给不同设备通过互联网(一般使用 HTTP 协议)进行通信和交换数据的一种服务.RESTful Web Servi ...

  5. 微软Power BI 每月功能更新系列——5月Power BI 新功能学习

    Power BI Desktop 5月份功能摘要 本月Power BI Desktop除了许多报表功能的更新,Power BI对条件格式进行了重大改进,可以对报表的任何字段(包括字符串和日期)进行条件 ...

  6. 2.28 查看webdriver API

    2.28 查看webdriver API(带翻译) 前言    前面都是点点滴滴的介绍selenium的一些api使用方法,那么selenium的api到底有多少呢?本篇就教大家如何去查看seleni ...

  7. Unity跳转场景进度条制作教程(异步加载)

    Unity跳转场景进度条制作 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分享 ...

  8. Vue.js学习使用心得(三)

    一.计算属性 计算属性关键词: computed <body> <div id="app"> <p>原始字符串: {{ message }}&l ...

  9. SQLI DUMB SERIES-1

    less-1 (1) 可以看到提示输入ID,而且less-1题目也有提到GET,因此试试以下操作: http: 结果: http: 结果: 现在可知,“ ' ”并没有被过滤,因此可以进行以下操作: h ...

  10. NFS相关、NFS服务端安装配置、exportfs命令、nfs客户端的问题

    1.NFS (network file system,基于RPC协议) 2.NFS服务端安装配置安装服务端:yum install nfs-utils rpcbind -y安装客户端:yum inst ...