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) ...
随机推荐
- Ubuntu 14.04 64bit 安装tensorflow(GPU版本)
本博客主要用于在Ubuntu14.04 64bit 操作系统上搭建google开源的深度学习框架tensorflow. 0.安装CUDA和cuDNN 如果要安装GPU版本的tensorflow,就必须 ...
- L2 Population 原理 - 每天5分钟玩转 OpenStack(113)
前面我们学习了 VXLAN,今天讨论跟 VXLAN 紧密相关的 L2 Population. L2 Population 是用来提高 VXLAN 网络 Scalability 的. 通常我们说某个系统 ...
- @Async in Spring--转
原文地址:http://www.baeldung.com/spring-async 1. Overview In this article we’ll explore the asynchronous ...
- Oracle启动报错ORA-27102解决
环境:RHEL5.5 + Oracle 10.2.0.4 此错误一般是因为数据库的初始化参数文件的内存设置不当导致.本例是因为操作系统参数设置问题导致. 当前现象:Oracle启动报错ORA-2710 ...
- 移动端用js与jquery实时监听输入框值的改动
背景: 在一次移动端H5开发中,需要监听输入框值的实时变动. onchange事件肯定抛弃,因为只能失去焦点才触发. 而keyPress在Android可以触发,iOS不可以. 又不想用Android ...
- [linux]挂载smb
什么是 smb 服务器消息区块(英语:Server Message Block,缩写为SMB,服务器消息区块),又称网络文件共享系统(英语:Common Internet File System,缩写 ...
- VS Extract Method
前言 看重构6.4Replace Temp with Query(以查询取代临时变量)中提到Replace Temp with Query往往是你运用Extract Method之前必不可少的一个步骤 ...
- 微信公众账号 token 验证失败 解决办法
问题:微信公众账号 开发过程中配置 token 提示 验证失败 如下图: 点击修改配置: 填写相关url与token(自定义):点击提交,会出现 出现这种情况,主要是对相关参数不熟悉,要了解url与 ...
- do{...}while(0)的妙用
在学习第一门编程语言时,就已经介绍了顺序分支.条件分支.循环分支.比如循环分支有for.while.do-while语句.在随后的学校及工作中,如果手工循环一般使用for.while,很少使用do-w ...
- C语言分割字符串
最近在做一道C语言题目的时候需要用到分割字符串,本来想自己手写的,也不会很麻烦,但想到其他语言都有分割字符串的库函数,C语言怎么会没有呢?所以,在网上搜了一搜,果然有这样的函数,还是很好用的,在此总结 ...