一、什么是可变长参数

可变长参数:顾名思义,就是函数的参数长度(数量)是可变的。比如 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 ;
}

三、 要点总结:

  1. 宏定义在 stdarg.h 中,所以使用时,不要忘了添加头文件。
  2. 注意相关宏的执行顺序。
  3. 设定一个参数结束标志(cplusplus 上说,va_arg 并不能确定哪个参数是最后一个参数)。
  4. 类型的匹配。

四、原理探究:

 // 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语言可变参函数探究的更多相关文章

  1. C语言中变参函数传参探究

    背景引入 近期在看一本书,叫做<嵌入式C语言自我修养>,写的内容对我帮助很大,是一本好书.在第6章,GNU C编译器扩展语法精讲一节,这本书给出了一些变参函数的例子: //1.变参函数初体 ...

  2. Go语言:变参函数

    变参函数: 函数中形式参数的数目通常是确定的,在调用的时候要依次传入与形式参数对应的所有实际参数,但是在某些函数的参数个数可以根据实际需要来确定,这就是变参函数. Go语言支持不定长变参,但是要注意不 ...

  3. C语言可变参函数分析

    code[class*="language-"], pre[class*="language-"] { color: rgba(51, 51, 51, 1); ...

  4. c语言学习-指针探究

    1:指针定义格式:格式:变量类型 *变量名用途:指针变量用于储存地址(only),也就是根据地址值,访问对应的存储空间. 注意.int *p 只能指向int类型的数据: 例: int a = 20; ...

  5. C语言变参函数/Variadic fucntion

    几个重要的 宏/类型 定义 Macros Defined in header <stdarg.h> va_start enables access to variadic function ...

  6. c /c++变参函数(转)

    原文转自 https://blog.csdn.net/wwzcx/article/details/8940092 实现c/c++语言的变参函数. 变参函数 :void fun(para,...) 变参 ...

  7. Is this Sentence Difficult? Do you Agree? -paper

    术语: 数据lemma:词根,词元(词的基本形式,如名词单数或动词的不定式形式) content words:实词part-of-speech:词性object-relative clauses an ...

  8. 《深入理解C#(第3版)》

    <深入理解C#(第3版)> 基本信息 原书名:C# in depth 作者: (英)Jon Skeet 译者: 姚琪琳 丛书名: 图灵程序设计丛书 出版社:人民邮电出版社 ISBN:978 ...

  9. PWN学习之格式化字符串漏洞

    目录 PWN学习之格式化字符串漏洞 格式化输出函数 格式化字符串漏洞 漏洞利用 使程序崩溃 栈数据泄露 任意地址内存泄漏 栈数据覆盖 任意地址内存覆盖 PWN学习之格式化字符串漏洞 格式化输出函数 可 ...

随机推荐

  1. Robot Framework自动化测试(一)---第一个脚本(转)

    最近工具中用Robot Framework框架来做自动化,所以,花时间学习了一下. =======所需环境=================== Python: https://www.python. ...

  2. 【Android】Android在AlertDialog使用大全

    package com.ceac.deng; import android.R.string; import android.support.v7.app.ActionBarActivity; imp ...

  3. Maven学习笔记(四):协调和依赖

    Maven协调具体的解释:      Maven定义了这样一组规则:世界上不论什么一个构件都能够使用Maven坐标唯一标识.Maven坐标的元素包含groupId.artifactId.version ...

  4. mysql_navicat_快捷键

    快捷键能节省很多时间,之前一直研究oracle,plsql有自定义自动补全, 比如 sf 直接回车 可以出现 select * from 等等(参照http://www.cnblogs.com/cph ...

  5. 深度解析javascript中的浅复制和深复制

    原文:深度解析javascript中的浅复制和深复制 在谈javascript的浅复制和深复制之前,我们有必要在来讨论下js的数据类型.我们都知道有Number,Boolean,String,Null ...

  6. PHP採集CSDN博客边栏的阅读排行

    项目中要用到採集的数据,所以就先拿CSDN博客来试了试.这里使用Simple HTML DOM(官网)这个库,它可以方便的遍历HTML文档. <?php include_once('simple ...

  7. POJ 2262 Goldbach&#39;s Conjecture(素数相关)

    POJ 2262 Goldbach's Conjecture(素数相关) http://poj.org/problem?id=2262 题意: 给你一个[6,1000000]范围内的偶数,要你将它表示 ...

  8. Linux httpd 跳转简单方法二

    使用mod_proxy 这种方法要添加上mod_proxy_http.so 在httpd.conf 中打开httpd-vhost 在 httpd-vhost 里面添加上 <VirtualHost ...

  9. 给phpcms v9加入一个主题radio无线电button,它可反复使用,以创建不同的专题部分内容编辑器,添加一个主题来定义自己的领域

    1. 2. 找到 phpcms\modules\special\templates中的special_add.tpl.php和special_edit.tpl.php文件 special_add.tp ...

  10. Swift 制作一个新闻通知中心插件1

    使用 Swift 制作一个新闻通知中心插件(1) 随着 iOS 8 的发布,苹果为开发者们开放了很多新的 API,而在这些开放的接口中 通知中心插件 无疑是最显眼的一个.通知中心就不用过多介绍了,相信 ...