va_list 使用总结
va_list 使用总结
- 前言
- 可变参数函数是什么?
- 示例
- 分析
- 参数 param_num 的作用
- 获取第一个可变参数
- 获取第二个可变参数
- 获取第三个可变参数
- 小总结
- va_list的常用方式
- 分析
- 小总结
前言
在可变参数函数中,经常可以看到va_list、va_start、va_arg、va_end
的使用。
可变参数函数是什么?
C语言中,printf
函数,就是一个可变参数函数, 传入的参数数量是不确定的,可以传入多个。
printf函数原型:
int printf(const char *format, ...)
其中 ...
,代表的就是可变参数,类似于省略号。
示例
下面通过一个简单的例子来体验可变参数函数。
static void va_list_test(int param_num, ...)
{int i = 0;va_list ap;va_start(ap, param_num);// 获取整型参数int arg1 = va_arg(ap, int);printf("arg1 = 0x%x\n", arg1);// 获取字符串char *arg2 = va_arg(ap, char *);printf("arg2 = %s\n", arg2);// 获取整型参数int arg3 = va_arg(ap, int);printf("arg3 = 0x%x\n", arg3);va_end(ap); // 注意需要 va_end(ap)
}int main()
{va_list_test(2, 0x55, "arg test", 0x66);return 0;
}
输出结果如下:
arg1 = 0x55
arg2 = arg test
arg3 = 0x66
分析
上述例子,分别传入了4个参数, 2, 0x55, "arg test", 0x66
, 可以从 va_list_test()函数传入参数的格式来看:
参数 param_num 的作用
为何需要param_num
的固定参数?
- 参数param_num, 即上述例子传入的
数字2
, 是固定参数。在上述例子无实际使用,用于给va_start
定位可变参数的位置。va_start(ap, param_num)
可以理解为,通过固定参数param_num
来找到可变参数存储的起始位置, 并保存到了ap
变量中。这个与函数调用过程,函数帧入栈有关系,不展开讨论。
分别获取参数的过程
获取第一个可变参数
- 参数0x55, 是整型参数, 由于
va_start(ap, param_num)
通过传入的参数param_num
定位到了可变参数的起始位置, 所以第一条获取整型参数 0x55, 用va_arg(ap, int)
来获取第一个可变参数,0x55, 根据ap
的位置,读取一个整型数值。
获取第二个可变参数
- 参数"arg test", 是字符串参数, 由于读取了0x55后, ap的位置已经改变,变成了第二个参数的起始位置, 所以
va_arg(ap, char *)
会以当前位置,获取一个字符串数值,所以得到"arg test"
。
获取第三个可变参数
- 最后一个参数 0x66, 也是同理, 继续
va_arg(ap, int)
获取一个int 参数。
小总结
- 需要理解第一个固定参数的作用, 即
va_start(ap, param_num)
, 同时需要关注ap
这个参数在获取可变参数中的意义, 可以理解为指针地址便宜,始终指向未获取的第一个可变参数地址 - 实验过程,尝试将可变参数1、2、3的获取顺序改变, 即获取顺序由
int 、 char *、int
修改为int 、int、char *
, 会出现,参数2 获取异常, 参数3 printf后出现段错误。 所以变量的获取顺序不能出错,否则会有异常。 va_start()
与va_end()
需要配对出现。 不使用va_end(ap)
的后果,猜测可能是会导致内存泄漏。 可以自行查询。
va_list的常用方式
在大部分的实际情况下,va_list都是与printf()函数的使用类似。
如以下例子
int va_list_test(char *fmt, ...)
{char out[1024] = {0};va_list ap;va_start(ap, fmt);vsnprintf(out, sizeof(out), fmt, ap);printf("%s", out);va_end(ap);
}int main()
{va_list_test("output : 0x%x, %s, 0x%x\n", 0x55, "arg test", 0x66);return 0;
}
输出结果如下:
output : 0x55, arg test, 0x66
分析
在上述例子中, 固定参数fmt
实际就是传入的 "output : 0x%x, %s, 0x%x\n"
, 三个可变参数,分别按照 %x、%s、%x的形式,通过vsnprintf()
格式化输入到out中。类似sprintf()
。
需要注意的是为什么用的vsnprintf()
先看下vsnprintf
函数的原型, 可以看到最后传入的一个参数,就是 va_list 变量,所以使用 vsnprintf
在上述例子中非常便捷。
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
小总结
- 注意vsnprintf()函数的使用方法。
- va_list常用情况经验积累。
va_list 使用总结相关推荐
- va_list和va_start和((A*)0)-a
C语言函数是从右到左入栈的 va_list ap;//=char *ap;(一个字符指针) va_start(ap,v) 中 ( ap = (va_list)_ADDRESSOF(v) + _INTS ...
- va_list、va_start和va_end使用
我们知道va_start,va_arg,va_end是在stdarg.h中被定义成宏的,由于1.硬件平台的不同 2.编译器的不同,所以定义的宏也有所不同. 在ANSI C中,这些宏的定义位于stdar ...
- linux c va_list 32位和64位的差异
在将程序从32位机器移植到64位机器的过程中经常出现一些奇奇怪怪的错误,这里记录一下在使用可变参数的过程中导致在32位机器上正常运行的程序移植到64位机器上之后出现段错误的发现过程以及解决方案. 首先 ...
- 理解可变参数va_list、va_start、va_arg、va_end原理及使用方法
参考: http://www.360doc.com/content/12/0309/10/4025635_192940551.shtml http://www.cnblogs.com/Annie ...
- c语言解决函数变参数问题 va_list
前言: 看到sprintf,swprintf之类的可变参数格式化函数,是否想过我们能写一个自定义的类似的函数吗?答案是很定的,下面来介绍一种方法,用va_list,va_start, va_end来实 ...
- 可变参数__VA_ARGS__使用和va_list使用小结
1. #用来把参数转换成字符串 #define P(A) printf("%s:%d\n",#A,A); #define SQUARE(x) printf("The sq ...
- va_list 简介
va_list 简介 (2011-04-16 10:31:17) 转载▼ 标签: 杂谈 分类:c/c 知识 va_list是一个宏,由va_start和va_end界定. typedefchar* v ...
- va_list/va_start/va_arg/va_end深入分析
va_list/va_start/va_arg/va_end这几个宏,都是用于函数的可变参数的. 我们来看看在vs2008中,它们是怎么定义的: 1: ///stdarg.h 2: #define v ...
- 转载--va_list
链接:va_list百科 1:概述 VA_LIST 是在c语言中解决变参问题的一组宏,所在头文件:#include <stdarg.h> 2:成员 #ifdef _M_ALPHA type ...
- va_start、va_end、va_list的使用
http://www.cnblogs.com/rainduck/archive/2010/11/10/1873417.html 1:当无法列出传递函数的所有实参的类型和数目时,可用省略号指定参数表 v ...
最新文章
- 《数据挖掘导论》实验课——实验一、数据处理之Numpy
- eeglab教程系列(2)-加载、显示数据
- myeclipse6.0.1(内置了eclipse)安装及其配置
- jdbc与java数据库编程_JDBC与JAVA数据库编程
- DNSPod揭6省断网重大事故内幕:网游私服恶斗
- 拓端tecdat|数据视域下图书馆话题情感分析
- js 中 ! + - ~ 符号和匿名函数
- 功能强大且易用的云打印解决方案
- oracle中ipad是什么意思,oracle 函数 Ipad的简单用法
- 《凤凰项目-一个IT运维从传奇故事》总结
- [ExtJS] Tpl模板中的extjs控件无法失焦处理
- 哪个106短信服务平台好?这4点要参考!
- QQ\微信等聊天记录备份与恢复
- win10 oracle怎样卸载,怎么完全卸载Oracle?(Win10) 以Oracle 11g为例
- 第二类换元法之倒代换习题
- sharding异常之no table route info
- 龙之谷2微信哪个服务器,龙之谷2微信区
- JQuery 添加元素(jquery对象),删除元素( .remove())
- VScode修改行间距
- GPS网的基线计算以及平差处理(使用Python绘制误差椭圆,C++处理数据并输出Qxx矩阵)