C/C++中带可变参数的函数
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++中带可变参数的函数的更多相关文章
- 【c++】类中带默认参数的函数
反思两个问题 1. 带默认参数的函数,为何声明.定义不能同时有参数? 2. 带默认参数的函数, 为何带默认参数的参数靠后站? 上程序 #include <iostream> #includ ...
- C函数和宏中的可变参数
一:调用惯例 函数的调用方和被调用方对函数如何调用应该有统一的理解,否则函数就无法正确调用.比如foo(int n, int m),调用方如果认为压栈顺序是m,n,而foo认为压栈顺序是n, m,那么 ...
- C语言中可变参数的函数(三个点,“...”)
C语言中可变参数的函数(三个点,“...”) 本文主要介绍va_start和va_end的使用及原理. 在以前的一篇帖子Format MessageBox 详解中曾使用到va_start和va_end ...
- [Effective JavaScript 笔记]第22条:使用arguments创建可变参数的函数
第21条讲述使用可变参数的函数average.该函数可处理任意数量的参数并返回这些参数的平均值. 如何创建可变参数的函数 1.实现固定元数的函数 书上的版本 function averageOfArr ...
- C# 中的可变参数方法(VarArgs)
首先需要明确一点:这里提到的可变参数方法,指的是具有 CallingConventions.VarArgs 调用约定的方法,而不是包含 params 参数的方法.可以通过MethodBase.Call ...
- PHP基础语法: echo,var_dump, 常用函数:随机数:拆分字符串:explode()、rand()、日期时间:time()、字符串转化为时间戳:strtotime()可变参数的函数:PHP里数组长度表示方法:count($attr[指数组]);字符串长度:strlen($a)
PHP语言原理:先把代码显示在源代码中,再通过浏览器解析在网页上 a. 1.substr; //用于输出字符串中,需要的某一部分 <?PHP $a="learn php"; ...
- 【转】C,C++中使用可变参数
可变参数即表示参数个数可以变化,可多可少,也表示参数的类型也可以变化,可以是 int,double还可以是char*,类,结构体等等.可变参数是实现printf(),sprintf()等函数的关键之处 ...
- C语言利用va_list、va_start、va_end、va_arg宏定义可变参数的函数
在定义可变参数的函数之前,先来理解一下函数参数的传递原理: 1.函数参数是以栈这种数据结构来存取的,在函数参数列表中,从右至左依次入栈. 2.参数的内存存放格式:参数的内存地址存放在内存的堆栈段中,在 ...
- c 可变参数 定义可变参数的函数
定义可变参数的函数,需要在stdarg.h头文件中定义的va_list类型和va_start.va_arg.va_end三个宏. 定义可变参数函数 va_list ap; //实际是定义一个指针va ...
随机推荐
- Delphi 10.3.1 TNetHttpClient在多线程中存在的问题及解决方法。
Delphi 10.3.1发布了,对10.3.0存在的各种问题,做了大量的修正.但听高勇说TNetHttpClient在多线程中存在问题,今天做了一下测试,确实如此,看来,还需要官方进一步修正! 具体 ...
- ie 折腾计(浏览器兼容性)
常见问题 IE:6.0,IE7.0,IE8.0之间的兼容独立说明 /*用于展示标签*/ <div class="jrx"></div> <style ...
- Python 多个装饰器装饰同一个函数
def wrapper1(fn): def inner(*args, **kwargs): print("1111111") ret = fn(*args, **kwargs) p ...
- For all entries in
Today I read about a blog explaining very detailedly on how to correctly use the key words FOR ALL E ...
- Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC 配置校验器
Spring4新特性——泛型限定式依赖注入 Spring4新特性——核心容器的其他改进 Spring4新特性——Web开发的增强 Spring4新特性——集成Bean Validation 1.1(J ...
- 带列表写入文件出错先 json.dumps
output = json.dumps(output, ensure_ascii=False).encode('utf-8')
- Unity 3D委托entrust
Unity 3D委托的多种用法 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分 ...
- P2157 [SDOI2009]学校食堂 (dp+状态压缩)
题目链接:传送门 题目: 题目描述 小F 的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭.学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满意的菜肴.当然,不同的人口味也不一定相同,但每个人 ...
- 下面的程序段创建了BufferedReader类的对象in,以便读取本机c盘my文件夹下的文件1.txt。File构造函数中正确的路径和文件名的表示是( )。
下面的程序段创建了BufferedReader类的对象in,以便读取本机c盘my文件夹下的文件1.txt.File构造函数中正确的路径和文件名的表示是( ). ./表示当前项目的路径../表示当 ...
- 计算字符串最后一个单词的长度,单词以空格隔开。 java算法
import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner in = ne ...