博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《OOC》笔记(3)——C语言变长参数va_list的用法
阅读量:5773 次
发布时间:2019-06-18

本文共 2037 字,大约阅读时间需要 6 分钟。

《OOC》笔记(3)——C语言变长参数va_list的用法

C语言中赫赫有名的printf函数,能够接受的参数数目不固定,这就是变长参数。C#里也有params这个关键字用来实现变长参数。

1 printf("Hello Mozart!");2 printf("Hello %s!", "Mozart");3 printf("%d: Hello %s!", 77, "Mozart");

用C实现一个能接受变长参数的函数

举例如下。

1 #include 
2 3 int add(const char * testString, int x, ...) 4 { 5 printf("%s\n", testString); 6 va_list list; 7 va_start(list, x); 8 int result = 0; 9 10 for(;;)11 {12 int p = va_arg(list, int);13 if(p == 0)14 break;15 result += p;16 }17 va_end(list); // cleanup , set 'lsit' to NULL18 return result;19 }20 21 /* error: ISO C requires a named argument before '...'22 void add2(...)23 {24 }25 */26 27 int main()28 {29 int result = add("test case 1: ", 1, 2, 3, 4, 5, 0);30 printf("%d\n", result);31 system("PAUSE");32 return 0;33 }34 35 /*36 This program print as follows:37 test case 1: 38 1539 */

编写使用变长参数的函数步骤如下。

  • 首先,引用stdarg.h。
  • 然后,在函数声明中用"..."表示这个函数能够使用变长参数。

注意,在"..."前面至少要有一个普通的参数。(可能非标准C不需要,不过我们还是保守一点最好)

  • 那么如何使用这些数目、类型都不确定的参数呢?

va_list类型的list变量可以遍历"..."中的参数。

用va_start()来初始化list变量。va_start()需要挨着"..."的左边那个参数名。(示例中的x)

va_arg()用于获取下一个参数值。这个参数值的类型你必须在编码时就能确定。

va_end()用于结束对list的遍历。之后你可以再次使用va_start()、va_arg()、va_end()来依次获取各个可变参数值。

 

注意事项

在add这个示例中,最后一个参数必须为0,add才能知道可变参数处理完毕。没有别的办法。也就是说,你不可能通过任何方式不借助外力就得知传进来的可变参数到底有几个。

在printf("%d, %s, %c", 1, "11", '1');函数中,printf会分析格式化参数"%d, %s, %c",它看到3个格式化输出符号,所以就认为传入了3个可变参数。如果你传入的多了或者少了,程序就可能出错。编译器无法检测这个错误。

list变量可以作为参数传递给其它函数。(如vprintf("xxx", list);)

在传递可变参数时,整型会作为int或long传递,float型会作为double传递。

va_arg()的第二个参数(示例中的int)不应太复杂。(这话很含糊)

总之,C语言中使用变长参数不是什么好的编程实践。能避免尽量避免。

 

原理是什么?

typedef char* va_list#define va_start(ap,v)(ap=(va_list)&v+_INTSIZEOF(v))#define va_arg(ap,t)(*(t*)((ap +=_INTSIZEOF(t))-_INTSIZEOF(t)))#define va_end(ap) ( ap = (va_list)0)

va_list是在stdio.h中定义的类型。va_start、va_arg、va_end是三个宏定义。

va_start把((v的地址)+(v的长度))赋给list。根据函数调用时形参的内存布局,这样list就指向了第一个可变参数。(示例中的2)

每次调用va_arg都会获得当前参数值,并将ap指针指向下一个参数。

调用va_end会将ap重置为0。

所以这个可变参数的原理就是一个迭代器,它在函数栈的参数上移动以依次获取可变参数。

转载地址:http://hpaux.baihongyu.com/

你可能感兴趣的文章
在SpringMVC利用MockMvc进行单元测试
查看>>
Nagios监控生产环境redis群集服务战
查看>>
Angular - -ngKeydown/ngKeypress/ngKeyup 键盘事件和鼠标事件
查看>>
Android BlueDroid(一):BlueDroid概述
查看>>
Java利用httpasyncclient进行异步HTTP请求
查看>>
循环多少次? 【杭电--HDOJ-1799】 附题+具体解释
查看>>
linux系统终端命令提示符设置(PS1)记录
查看>>
C++运算符重载
查看>>
【Web】URI和URL,及URL的编码
查看>>
宿舍局域网的应用
查看>>
html代码究竟什么用途
查看>>
oracle的substr函数的用法
查看>>
QT 数据库编程四
查看>>
npm下载包时代理配置
查看>>
全球十大理论
查看>>
model.addAttribute("student",student)——渲染
查看>>
JavaWeb开发之普通图片验证码生成技术与算术表达式验证码生成技术
查看>>
python和pywin32实现窗口查找、遍历和点击
查看>>
第二章 概率图模型的基本原理
查看>>
Hadoop HDFS编程 API入门系列之路径过滤上传多个文件到HDFS(二)
查看>>