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. centos安装python3虚拟环境和python3安装

    1.本文的系统命令一般会在语句前加上#号,以区分系统命令及其他内容.输入命令时,无需输入#号. # yum install vim 2.本文系统输出的信息,会在前面加上>>号. # whi ...

  2. 本周java 学习进度报告

    本周java 学习进度报告 本周对我的感触很深,因为这是我初学java 语言的第一周,我认识到java 和c语言是有很多的不同之处和相同之处.我这几天几乎是在研究java 基础入门知识,而并没有太多的 ...

  3. 设置idea文件类型

  4. linux下开启oracle服务和开启监听

    su - oracle  切换到oracle用户模式下 sqlplus /nolog  //登录sqlplus SQL> connect /as sysdba  //连接oracle SQL&g ...

  5. 卷积神经网络 CNN 笔记

    链接: 在训练卷积神经网络(CNN)的某一个卷积层时,实际上是在训练一系列的滤波器(filter).简单来说,训练CNN在相当意义上是在训练每一个卷积层的滤波器.让这些滤波器组对特定的模式有高的激活, ...

  6. I2C总线以及GPIO模拟I2C

    ·I2C总线的一些特征: 1. 只要求两条总线,一条串行数据线(SDA),一条串行时钟线(SCL) 2. 两个连接到总线的器件都可以通过唯一的地址和一直存在的简单的主机/从机系统软件设定的地址:主机可 ...

  7. UDP方式实现广域网的P2P通信

    最近在研究P2P通信,希望能够穿透路由器. 当前的做法只是使用TCP协议进行客户端与服务器端通信,使用UDP协议进行客户端之间的打洞操作,UDP的方式的源码在下方. 一直没有实现TCP的打洞,如果有实 ...

  8. Unity 3D接入ShareSDK流程2

    Unity开发VR之Vuforia 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- ...

  9. PTA——支票面额

    PTA 7-38 支票面额 #include<stdio.h> int main() { int n,f,y; ; scanf("%d",&n); ; flag ...

  10. 【BZOJ2300】【SCOI2011】糖果

    差点就忘了还有差分约束这个东西……看见了就要学习一个 原题: 幼儿园里有N个小朋友,lxhgww老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果.但是小朋友们也有嫉妒心,总是会提出一些要 ...