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. JavaScript权威指南--立即执行函数

    千万不要停下追逐梦想的脚步 (function(){ //execute this method immediatly. //content... }());

  2. partial、struct、interface与C#和CLR的关系

    partial.struct.interface是C#编译器特有的,CLR对此一无所知.

  3. 转——.ashx文件与.ashx.cs

    作者:PBDragon 原文连接:http://www.cnblogs.com/PBDragon/p/3811831.html 如果项目是“新建网站”,添加的ashx是没有ashx.cs的:如果是新建 ...

  4. 江西财经大学第一届程序设计竞赛 D

    链接:https://www.nowcoder.com/acm/contest/115/D来源:牛客网 题目描述 事情,是这样的. 有这么一天双休日的中午. 我刚把我衣服扔进了洗衣机,然后拿了个小板凳 ...

  5. day19 MRO C3算法 super()

    1. MRO(Method Resolution Order):方法解析顺序,主要用于在多继承时判断调的属性的路径(来自于哪个类). 1.Python语言包含了很多优秀的特性,其中多重继承就是其中之一 ...

  6. STL之set(唯一且有顺序)

    set作为一个容器也是用来存储同一数据类型的数据类型,并且能从一个数据集合中取出数据, 在set中每个元素的值都唯一,而且系统能根据元素的值自动进行排序.应该注意的是set中数元素的值不能直接被改变. ...

  7. web常见测试点总结

    上周五小组内对Web的常见测试点进行了交流学习,虽然这些信息网上一搜都一大把,但整理的过程中自己脑袋瓜里又重新回顾了一遍,大家都很认真的在学习,互相补充着,现总结如下,欢迎同行留言 一.新增.修改 用 ...

  8. form表单序列化数据之后,追加额外数据

    form表单序列化数据之后追加额外数据多使用在js中,下面是追加额外数据的代码: <span style="font-size:18px;">$.param({'inv ...

  9. C++中遇到的各种小问题

    lpcwstr类型问题 在使用VS2010开发C++程序时,由于系统默认字符集是unicode字符集,造成与早期的字符串格式不兼容问题 ①Properties — Configuration Prop ...

  10. Beam概念学习系列之PCollection数据集

    不多说,直接上干货! PCollection数据集  PCollection是Apache Beam中数据的不可变集合,可以是有限的数据集合也可以是无限的数据集合. 有限数据集,这种一般对应的是批处理 ...