1.可变参函数的原理

  C/C++函数的参数是存放在栈区的,并且参数的入栈是从参数的右边开始,即最后一个参数先入栈,而第一个参数最后才入栈,所以,根据栈的后进先出性质,函数总能找到第一个参数。所以,可变参函数的实现必须能够从已知参数中获取到函数所需要参数的个数,否则怎么知道传了几个参数呢。

  例如printf函数,第一个参数就是一个格式串,而后面所需要的参数个数能够从格式串中推得。

2.可变参函数的设计

  标准头文件<stdarg.h>提供了一套对可变参函数的实现机制,所以编写可变参函数需要包含该头文件。

#include<stdarg.h>

  C语言的头文件<stdarg.h>提供了一个数据类型va_list和三个宏(va_start、va_arg和va_end),得用它们来实现可变参。va_list是一般是一个char指针(即字符串指针),用来指向可变参的。

  来看看这四个玩意一般是怎么定义的。

typedef char *  va_list; //就是个指针呀
#define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )  // 这个有什么用你得自己看,我管不住你了。可以不看的。

#define va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )   // 将ap指向v之后的位置
#define va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) // 取出ap的值,并将ap指向下一个位置。t就是类型,可以是int,double等等
#define va_end(ap)      ( ap = (va_list)0 )  // 置空
 

3.可变长参数函数的实现

  先上例子,hello world!

  实例1::实现求和函数,参数个数可变

 int sum(int n, ...)
{
va_list arg_ptr;
va_start(arg_ptr, n);
5 int nRes = 0;
for(int i=0; i < n; ++i)
{
int temp = va_arg(arg_ptr, int); // 逐个参数取出来
nRes += temp;  // 求和
}
va_end(arg_ptr); // 养成习惯
return nRes;
}

  实例2:实现printf的功能

 void myPrintf(const char *strFormat, ...)
{
if(NULL==strFormat) return;
va_list arg_ptr;
va_start(arg_ptr, strFormat);
char strInfo[] = {}; // 小心别溢出?
vsprintf(strInfo, strFormat, arg_ptr); // 按格式打印到strInfo,功能类似sprintf
fputs(strInfo, stdout); // 输出
va_end(arg_ptr);
}
 
 

完整例子,G++编过测过了。

 #include <iostream>
#include <stdarg.h>
#include <stdio.h> int sum(int n, ...)
{
va_list arg_ptr;
int i = , nRes = ;
va_start(arg_ptr, n);
for(; i < n; ++i)
{
int temp = va_arg(arg_ptr, int);
nRes += temp;
}
va_end(arg_ptr);
return nRes;
} void myPrintf(const char *strFormat, ...)
{
if(NULL==strFormat) return;
va_list arg_ptr;
va_start(arg_ptr, strFormat);
char strInfo[] = {}; // 小心别溢出?
vsprintf(strInfo, strFormat, arg_ptr); // 按格式打印到strInfo,功能类似sprintf
fputs(strInfo, stdout);
va_end(arg_ptr);
} int main()
{
myPrintf("%s %d\n","the result is ", sum(, , , , ));
return ;
}

example

(1) va_list的定义即例子见 http://www.cplusplus.com/reference/cstdarg/va_list/ 
(2) 各个平台的实现可能是不一样的,如va_end的实现,故最好先了解你所用的平台。
(3) 实际使用时还有更多的东西要考虑,不仅仅像上面那么简单。
 

花3分钟了解下C/C++中的函数可变参简单实现的更多相关文章

  1. 【MySQL】花10分钟阅读下MySQL数据库优化总结

    1.花10分钟阅读下MySQL数据库优化总结http://www.kuqin.com2.扩展阅读:数据库三范式http://www.cnblogs.com3.my.ini--->C:\Progr ...

  2. C/C++中substr函数的应用(简单讲解)

    substr(字符串,截取开始位置,截取长度) //返回截取的字 substr('Hello World',0,1) //返回结果为 'H'  *从字符串第一个字符开始截取长度为1的字符串 subst ...

  3. 还在用Postman?来,花2分钟体验下ApiPost的魅力

    2分钟玩转APIPOST 本文通过简单介绍如何利用ApiPost调试接口和快速的生成接口文档,让您初步体验ApiPost的魅力! 1. API写完想要测试?试试模拟发送一次请求 新建接口,我想模拟发送 ...

  4. [转]Android下拉刷新完全解析,教你如何一分钟实现下拉刷新功能

    版权声明:本文出自郭霖的博客,转载必须注明出处. 转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9255575 最近项目中需要用到L ...

  5. 2分钟 windows下sublime text 3安装git插件:

    12:35 2015/11/182分钟 windows下sublime text 3安装git插件:推荐博客:http://blog.csdn.net/naola2001/article/detail ...

  6. 5分钟 wamp下php phpmaile发送qq邮件 2015最新方法说明

    13:40 2015/11/20 5分钟 wamp下php phpmaile发送qq邮件 2015最新方法说明 关键点:现在qq邮箱开通smtp服务后会给你一个很长的独立新密码,发邮件配置中的密码需要 ...

  7. Android下拉刷新完全解析,教你如何一分钟实现下拉刷新功能 (转)

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9255575 最 近项目中需要用到ListView下拉刷新的功能,一开始想图省事,在 ...

  8. Win8下在Vmware11中安装使用苹果系统OS X 10.10

    原文:Win8下在Vmware11中安装使用苹果系统OS X 10.10   近来因为需要做 iOS 的项目,所以需要多花一些时间看看敲敲代码.因为自己手头上并没有 Mac(过年为了闲的时候能玩玩游戏 ...

  9. 花十分钟,让你变成AI产品经理

    花十分钟,让你变成AI产品经理 https://www.jianshu.com/p/eba6a1ca98a4 先说一下你阅读本文可以得到什么.你能得到AI的理论知识框架:你能学习到如何成为一个AI产品 ...

随机推荐

  1. Unity 动画系统 Animation和Animator 常用小功能

  2. Launch iCar Scan Android Scanner Support Bluetooth X431 iDiag Update Version

    Autonumen.com release new Launch iCar Scan for Android,Launch iCarScan Bluetooth Scanner is update v ...

  3. Office 2016 word无法粘贴(Ctrl + V)

    最近下载了一个 Office 2016 专业版 使用,发现 word 无法使用 Ctrl + V 粘贴东西,由于经常需要复制粘贴东西,无法粘贴影响很大 查了很多资料,尝试过很多的方法,终于发现问题的所 ...

  4. Linux Vi/Vim 在插入模式下键盘右边数字键输入异常

    问题:Linux在 Vi/Vim 在编辑文件时遇到一个问题,当我在 Insert 模式下进行修改文件内容的时候,用到了键盘(104键,右边带数字键那种)进行数字输入,当我输入数字 “5” 时,插入的数 ...

  5. 安装NetCDF及HDF5

    平台信息 Description: CentOS Linux release 7.6.1810 (Core) 安装步骤 下载NetCDF.HDF5.zlib.curl[使用wget命令即可] 解包:t ...

  6. 登陆jq表单验证及jqcookie记住密码实例

    <p><%@ page contentType="text/html; charset=utf-8"%> <%@taglib prefix=" ...

  7. My first Python program(附增加清屏方法)

    #TempConvert.py TempStr = input("请输入带有符号的温度值:") if TempStr[-1] in ['F', 'f']: C = (eval(Te ...

  8. 牛客网Java刷题知识点之代码块(局部代码快、构造代码块、静态代码块)

    不多说,直接上干货! 代码块包括局部代码快.构造代码块.静态代码块. 代码块,就是一段独立的代码空间. 1.局部代码快 对局部变量的生命周期进行控制. 2.构造代码块 对所有对象进行初始化. 3.静态 ...

  9. HDU 4364——Matrix operation——————【模拟题】

    Matrix operation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  10. AJAX重点知识的心得体会

    下面就为大家带来一篇 AJAX重点知识的心得体会.学习还是有点帮助的,给大家做个参考吧. AJAX是什么? 是Asynchronous Javascript And XML的首字母的缩写, 它不是一门 ...