c语言可变参函数探究
一、什么是可变长参数
可变长参数:顾名思义,就是函数的参数长度(数量)是可变的。比如 C 语言的 printf 系列的(格式化输入输出等)函数,都是参数可变的。下面是 printf 函数的声明:
int printf ( const char * format, ... );
可变参数函数声明方式都是类似的。
二、如何实现
C语言可变参数通过三个宏(va_start、va_end、va_arg)和一个类型(va_list)实现的,
void va_start ( va_list args, paramN );
参数:
args: 可变参数列表地址
paramN: 确定的参数
功能:初始化可变参数列表(把函数在 paramN 之后的参数地址放到 args 中)。
void va_end ( va_list args );
功能:关闭初始化列表(将 args 置空)。
type va_arg ( va_list args, type );
功能:返回下一个参数的值。
va_list :存储参数的类型信息。
好了,综合上面3个宏和一个类型可以猜出如何实现C语言可变长参数函数:用 va_start 获取参数列表(的地址)存储到 args 中,用 va_arg 逐个获取值,最后用va_end 将 args置空。
#include <stdio.h>
#include <stdarg.h> #define END -1 int va_sum (int first_num, ...)
//省略号代表可变函数
{
// (1) 定义参数列表
va_list args;
// (2) 初始化参数列表
va_start(args, first_num); int result = first_num;
int temp = ;
// 获取参数值
while ((temp = va_arg(args, int)) != END)
{
result += temp;
} // 关闭参数列表
va_end(args); return result;
} int main ()
{
int sum_val = va_sum(, , , , , END);
printf ("%d", sum_val);
return ;
}
三、 要点总结:
- 宏定义在 stdarg.h 中,所以使用时,不要忘了添加头文件。
- 注意相关宏的执行顺序。
- 设定一个参数结束标志(cplusplus 上说,va_arg 并不能确定哪个参数是最后一个参数)。
- 类型的匹配。
四、原理探究:
// stdarg.h
#define va_start _crt_va_start
#define va_arg _crt_va_arg
#define va_end _crt_va_end
// vadefs.h
typedef char * va_list;
#define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _crt_va_end(ap) ( ap = (va_list)0 )
#define _ADDRESSOF(v) ( &(v) )
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
即:将函参在栈中的地址记录到va_list变量中,然后逐个读取变量的值;
五、总结:
c语言的可变长参数令人着迷,细想实现的思路,无非就是首先要知道参数在栈中,然后获取其值即可,其他就是细节的问题了;
c语言可变参函数探究的更多相关文章
- C语言中变参函数传参探究
背景引入 近期在看一本书,叫做<嵌入式C语言自我修养>,写的内容对我帮助很大,是一本好书.在第6章,GNU C编译器扩展语法精讲一节,这本书给出了一些变参函数的例子: //1.变参函数初体 ...
- Go语言:变参函数
变参函数: 函数中形式参数的数目通常是确定的,在调用的时候要依次传入与形式参数对应的所有实际参数,但是在某些函数的参数个数可以根据实际需要来确定,这就是变参函数. Go语言支持不定长变参,但是要注意不 ...
- C语言可变参函数分析
code[class*="language-"], pre[class*="language-"] { color: rgba(51, 51, 51, 1); ...
- c语言学习-指针探究
1:指针定义格式:格式:变量类型 *变量名用途:指针变量用于储存地址(only),也就是根据地址值,访问对应的存储空间. 注意.int *p 只能指向int类型的数据: 例: int a = 20; ...
- C语言变参函数/Variadic fucntion
几个重要的 宏/类型 定义 Macros Defined in header <stdarg.h> va_start enables access to variadic function ...
- c /c++变参函数(转)
原文转自 https://blog.csdn.net/wwzcx/article/details/8940092 实现c/c++语言的变参函数. 变参函数 :void fun(para,...) 变参 ...
- Is this Sentence Difficult? Do you Agree? -paper
术语: 数据lemma:词根,词元(词的基本形式,如名词单数或动词的不定式形式) content words:实词part-of-speech:词性object-relative clauses an ...
- 《深入理解C#(第3版)》
<深入理解C#(第3版)> 基本信息 原书名:C# in depth 作者: (英)Jon Skeet 译者: 姚琪琳 丛书名: 图灵程序设计丛书 出版社:人民邮电出版社 ISBN:978 ...
- PWN学习之格式化字符串漏洞
目录 PWN学习之格式化字符串漏洞 格式化输出函数 格式化字符串漏洞 漏洞利用 使程序崩溃 栈数据泄露 任意地址内存泄漏 栈数据覆盖 任意地址内存覆盖 PWN学习之格式化字符串漏洞 格式化输出函数 可 ...
随机推荐
- webservice发送字符串
假设只是发送一个字符串client,这是很easy,只需要输入xfire包,编写接口,编写的实现方法.变化. 假设你要传输的数组或自定义类.到用于接口准备的需要agexis文件.更复杂. 尝试传输这些 ...
- 在四川大学的第二个冠军游戏在线编程:Peter的X
四川大学线下编程比赛第二题:Peter的X 公布公司: 有 效 期: CSDN 2014-09-27至2015-09-26 难 度 等 级: 答 题 时 长: 编程语言要求: 120分钟 C C++ ...
- kobject_create_and_add
本文来源于源linux 3.14.3版本号/lib/kobject.c文件 /** * kobject_create_and_add - 动态地创建kobject结构和寄存器sysfs * * ...
- C# ICSharpCode.SharpZipLib
C# ICSharpCode.SharpZipLib.dll文件压缩和解压功能类整理,上传文件或下载文件很常用 工作中我们很多时候需要进行对文件进行压缩,比较通用的压缩的dll就是ICSharpCod ...
- hdu What Are You Talking About(map)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1075 map简单应用 代码: #include <stdio.h> #include &l ...
- hibernate 一对多关联关系(具体分析)
在领域模型中, 类与类之间最普遍的关系就是关联关系. 在 UML 中, 关联是有方向的. 以 Customer 和 Order 为例: 一个用户能发出多个订单, 而一个订单仅仅能属于一个客户. 从 ...
- request的setAttribute()怎么用的?
request.setAttribute()怎么用的?JSP1代码String [] test=new String[2];test[0]="1";test[1]="2& ...
- MVC EF 修改 封装类 通用泛型方法(一)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.D ...
- 详解linux vi命令用法
vi是所有UNIX系统都会提供的屏幕编辑器,它提供了一个视窗设备,通过它可以编辑文件.当然,对UNIX系统略有所知的人,或多或少都觉得vi超级难用,但vi是最基本的编辑器,所以希望读者能好好把它学起来 ...
- DataTable相关操作,筛选,取前N条数据,获取指定列数据
DataTable相关操作,筛选,取前N条数据,获取指定列数据2013-03-12 14:50 by Miracle520, 2667 阅读, 0 评论, 收藏, 编辑 1 #region DataT ...