va_start和va_end使用详解
本文主要介绍va_start和va_end的使用及原理。
介绍这两个宏之前先看一下C中传递函数的参数时的用法和原理:
1.在C中,当我们无法列出传递函数的所有实参的类型和数目时,可以用省略号指定参数表
void foo(parm_list,...);
2.函数参数的传递原理
函数参数是以数据结构:栈的形式存取,从右至左入栈。
void func(int x, float y, char z);
那么,调用函数的时候,实参 char z 先进栈,然后是 float y,最后是 int x,因此在内存中变量的存放次序是 x->y->z,因此,从理论上说,我们只要探测到任意一个变量的地址,并且知道其他变量的类型,通过指针移位运算,则总可以顺藤摸瓜找到其他的输入变量。
typedef char* va_list;
void va_start ( va_list ap, prev_param ); /* ANSI version */
type va_arg ( va_list ap, type );
void va_end ( va_list ap );
va_list 是一个字符指针,可以理解为指向当前参数的一个指针,取参必须通过这个指针进行。
<Step 1> 在调用参数表之前,定义一个 va_list 类型的变量,(假设va_list 类型变量被定义为ap);
<Step 2> 然后应该对ap 进行初始化,让它指向可变参数表里面的第一个参数,这是通过 va_start 来实现的,第一个参数是 ap 本身,第二个参数是在变参表前面紧挨着的一个变量,即“...”之前的那个参数;
<Step 3> 然后是获取参数,调用va_arg,它的第一个参数是ap,第二个参数是要获取的参数的指定类型,然后返回这个指定类型的值,并且把 ap 的位置指向变参表的下一个变量位置;
<Step 4> 获取所有的参数之后,我们有必要将这个 ap 指针关掉,以免发生危险,方法是调用 va_end,他是输入的参数 ap 置为 NULL,应该养成获取完参数表之后关闭指针的习惯。说白了,就是让我们的程序具有健壮性。通常va_start和va_end是成对出现。
#include <iostream.h>
void fun(int a, ...)
{
int *temp = &a;
temp++;
for (int i = 0; i < a; ++i)
{
cout << *temp << endl;
temp++;
}
}
int main()
{
int a = 1;
int b = 2;
int c = 3;
int d = 4;
fun(4, a, b, c, d);
system("pause");
return 0;
}
Output::
1
2
3
4
在函数体中声明一个va_list,然后用va_start函数来获取参数列表中的参数,使用完毕后调用va_end()结束。像这段代码:
void TestFun(char* pszDest, int DestLen, const char* pszFormat, ...)
{
va_list args;
va_start(args, pszFormat); //一定要“...”之前的那个参数
_vsnprintf(pszDest, DestLen, pszFormat, args);
va_end(args);
}
#include 〈stdio.h〉
#include 〈string.h〉
#include 〈stdarg.h〉
/*函数原型声明,至少需要一个确定的参数,注意括号内的省略号*/
int demo( char, ... );
void main( void )
{
demo("DEMO", "This", "is", "a", "demo!", "");
}
/*ANSI标准形式的声明方式,括号内的省略号表示可选参数*/
int demo( char msg, ... )
{
/*定义保存函数参数的结构*/
va_list argp;
int argno = 0;
char para;
/*argp指向传入的第一个可选参数,msg是最后一个确定的参数*/
va_start( argp, msg );
while (1)
{
para = va_arg( argp, char);
if ( strcmp( para, "") == 0 )
break;
printf("Parameter #%d is: %s\n", argno, para);
argno++;
}
va_end( argp );
/*将argp置为NULL*/
return 0;
}
以上是对va_start和va_end的介绍。
转载地址:http://www.cnblogs.com/hanyonglu/archive/2011/05/07/2039916.html
va_start和va_end使用详解的更多相关文章
- [转载]va_start和va_end使用详解
va_start和va_end使用详解 原文地址:http://www.cnblogs.com/hanyonglu/archive/2011/05/07/2039916.html 本文主要介绍va_s ...
- [转载]C/C++可变参数之va_start和va_end使用详解
本文主要介绍va_start和va_end的使用及原理. 在以前的一篇帖子Format MessageBox 详解中曾使用到va_start和va_end这两个宏,但对它们也只是泛泛的了解. 介绍这两 ...
- [转]va_start和va_end使用详解
转载地址:http://www.cnblogs.com/hanyonglu/archive/2011/05/07/2039916.html 本文主要介绍va_start和va_end的使用及原理. ...
- va_start和va_end使用详解(转载)
转自:http://www.cnblogs.com/hanyonglu/archive/2011/05/07/2039916.html 本文主要介绍va_start和va_end的使用及原理. 在以前 ...
- 20160129.CCPP体系详解(0008天)
程序片段(01):函数.c+call.c+测试.cpp 内容概要:函数 ///函数.c #include <stdio.h> #include <stdlib.h> //01. ...
- 20160217.CCPP体系详解(0027天)
程序片段(01):TestCmd.c 内容概要:管道_字符串 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include < ...
- C++可变参数列表处理宏va_list、va_start、va_end的使用
VA_LIST是在C语言中解决变参问题的一组宏他有这么几个成员: 1)va_list型变量: #ifdef _M_ALPHA typedef struct{ char* a0; /* ...
- 【转】C++可变参数列表处理宏va_list、va_start、va_end的使用
VA_LIST是在C语言中解决变参问题的一组宏他有这么几个成员: 1)va_list型变量: #ifdef _M_ALPHA typedef struct{ char* a0; /*po ...
- 【转】va_list 详解
原文出自http://www.cppblog.com/xmoss/archive/2009/07/20/90680.html VA_LIST 是在C语言中解决变参问题的一组宏 他有这么几个成员: 1) ...
随机推荐
- WebView 与PC机Chrome配合调试
参考自http://www.cnblogs.com/terrylin/p/4606277.html 移动端WebView开发调试:Chrome远程调试 Chrome DevTools调试移动设备Bro ...
- How to write perfect C code
Several days ago, I was involved in an argument about choice of C or C++. What I ignored was "l ...
- UWP开发之Mvvmlight实践一:如何在项目中添加使用Mvvmlight(图文详解)
最近一直在做UWP开发,为了节省成本等等接触到MVVMlight,觉得有必要发点时间研究它的用法与实现原理才行.如果有问题的地方或者有好的建议欢迎提出来. 随着移动开发的热门,Mvvmlight在An ...
- 在IE11下设置SharePoint Server 2013却遇到“需要 Internet Explorer 才能使用此功能。”的解决办法
就在昨天顺利升级到Windows 8.1 随之IE也升级到了IE11,但是当打开IE11设置SharePoint Server 2013的时候遇到了一些小情况: Figure 1使用Windows 8 ...
- 小身材大用途,用PrimusUI驾驭你的页面
“PrimusUI”是自己在借鉴了如今网上很多开源的UI库,再经过自己整理加工的一个简单代码集合. 每个功能块的CSS代码都很少,力求简单易懂,低门槛,代码可根据自己实际情况轻易修改,改到符合自己场景 ...
- dapper-dot-net用法及其扩展系列
dapper-dot-net用法及其扩展系列 虽然已经一段时间没写.net了,但是昨天看了下dapper和Dapper-Extensions在github仍然有更新,他们的受欢迎程度可想而知.所以想把 ...
- Sql Server 聚集索引扫描 Scan Direction的两种方式------FORWARD 和 BACKWARD
最近发现一个分页查询存储过程中的的一个SQL语句,当聚集索引列的排序方式不同的时候,效率差别达到数十倍,让我感到非常吃惊 由此引发出来分页查询的情况下对大表做Clustered Scan的时候, 不同 ...
- JavaScript作用域链
之前写过一篇JavaScript 闭包究竟是什么的文章理解闭包,觉得写得很清晰,可以简单理解闭包产生原因,但看评论都在说了解了作用域链和活动对象才能真正理解闭包,起初不以为然,后来在跟公司同事交流的时 ...
- Sublime插件支持Sass编译和Babel解析ES6 & .sublime-build文件初探
用Sublime Text蛮久了,配置配来配去的,每次换电脑都得重头再配过,奈何人老了脑子不中用了,得好好整理一些,下次换电脑就有得参考了.. 同事说,他的WebStorm简直太方便,自身集成了很多方 ...
- 匿名方法与Lambda表达式
1.匿名方法 在学习委托时,我们知道委托实例至少要绑定一个方法才能使用,而调用委托实际上是调用了它所关联地方法.一般来说,需要定义一个与委托签名相符的方法,并使之与委托变量关联.如以下代码: Acti ...