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

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

 printf("Hello Mozart!");
printf("Hello %s!", "Mozart");
printf("%d: Hello %s!", , "Mozart");

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

举例如下。

 #include <stdarg.h>

 int add(const char * testString, int x, ...)
{
printf("%s\n", testString);
va_list list;
va_start(list, x);
int result = ; for(;;)
{
int p = va_arg(list, int);
if(p == )
break;
result += p;
}
va_end(list); // cleanup , set 'lsit' to NULL
return result;
} /* error: ISO C requires a named argument before '...'
void add2(...)
{
}
*/ int main()
{
int result = add("test case 1: ", , , , , 5, );
printf("%d\n", result);
system("PAUSE");
return ;
} /*
This program print as follows:
test case 1:
15
*/

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

  • 首先,引用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。

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

《OOC》笔记(3)——C语言变长参数va_list的用法的更多相关文章

  1. C语言变长参数实现

    #include<stdio.h> #include<string.h> #include<stdarg.h> /***编写可变长参数列表的函数案例*/ /* vo ...

  2. 介绍C++11标准的变长参数模板

    目前大部分主流编译器的最新版本均支持了C++11标准(官方名为ISO/IEC14882:2011)大部分的语法特性,其中比较难理解的新语法特性可能要属变长参数模板(variadic template) ...

  3. C++中的变长参数

    新参与的项目中,为了使用共享内存和自定义内存池,我们自己定义了MemNew函数,且在函数内部对于非pod类型自动执行构造函数.在需要的地方调用自定义的MemNew函数.这样就带来一个问题,使用stl的 ...

  4. Scala 变长参数

    如果Scala定义变长参数 def sum(i Int*), 那么调用sum时,可以直接输入sum(1,2,3,4,5) 但是不可以sum(1 to 5) 必须要将1 to 5 强制为seq sum( ...

  5. C++11变长参数模板

    [C++11变长参数模板] C++03只有固定模板参数.C++11 加入新的表示法,允许任意个数.任意类别的模板参数,不必在定义时将参数的个数固定. 实参的个数也可以是 0,所以 tuple<& ...

  6. 【Unix环境高级编程】编写变长参数函数

    文件的格式输入输出函数都支持变长参数.定义时,变长参数列表通过省略号'...'表示, 因此函数定义格式为: type 函数名(parm1, parm2,parmN,...); Unix的变长参数通过v ...

  7. java常量和变量的定义规则,变长参数的使用

    首先是定义的一般规则,类名首字母全部大写,常量全部大写用下划线分隔,变量用驼峰形式.注意使用long赋值用L时不能写小写的L要写大写的,不然会和数字“1”傻傻分不清. 下面是举例: public cl ...

  8. Lua 变长参数(variable number of arguments)

    lua变长参数 function add ( ... ) for i, v in ipairs{...} do print(i, ' ', v) end end add(1, 2, 'sdf') lu ...

  9. 【小白学Lua】之Lua变长参数和unpack函数

    一.简介 Lua的变长参数和unpack函数在实际的开发中应用的还挺多的,比如在设计print函数的时候,需要支持对多个变量进行打印输出,这时我们就需要用到Lua中的变长参数和unpack函数了. 二 ...

随机推荐

  1. .Net多文件同时上传(Jquery Uploadify)

    前提:领导给了我一个文件夹,里面有4000千多张产品图片,每张图片已产品编号+产品名称命名,要求是让我把4000多张产品图片上传到服务器端,而且要以产品编码创建n个文件夹,每张图片放到对应的文件夹下. ...

  2. rspec中的shared_examples与shared_context有什么不同

    What is the real difference between shared_examples and shared_context ? My observations : I can tes ...

  3. 一个书店管理系统java

    自己的第一个小程序 ps:书是在集合里面后面文件处理的有一点小问题,希望有人会给点意见 //客户类 import java.io.Serializable; public class Customer ...

  4. ZOJ3791_An Easy Game

    给出两个等长的字符串,每次需要改变m个数字,每次必须改变k个数字,求从第一个串变化到第二个串的方案数. DP.f[i][j]改变i步后,有j个位置被改变的方案数.然后直接枚举当前改变的几个位置是前面重 ...

  5. javascript鸭式辩型法实现接口

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...

  6. 猜数字 事先给定一个数字,然后让用户猜3次,猜不中就输了,猜中就赢了。 每次猜错,给出提示,less or big

    c = 0a = 10while c <3:    b = int(raw_input("请输入数字"))    if b == a:        print " ...

  7. Swift - mutating关键字的使用

    转载自:http://www.jianshu.com/p/14cc9d30770a  感谢作者:此ID想了很久 Swift中protocol的功能比OC中强大很多,不仅能再class中实现,同时也适用 ...

  8. 【12-JDBC编程】

    JDBC编程 JDBC概述 •通过使用JDBC API,Java程序可以非常方便地操作各种主流数据库,这是使Java语言的巨大 魅力所在.而且由于Java语言的跨平台特性,所以使用JDBC API所编 ...

  9. IT小喇叭-企业品牌宣传、产品营销推广的首选

    IT小喇叭-企业品牌宣传.产品营销推广的首选 IT小喇叭,成立于2015年6月初,成都芮嘉科技有限公司旗下产品,主要进行媒体资源整合.宣传报道:使移动互联网等相关企业的产品宣传.品牌营销变得更加方便. ...

  10. CodeForces 742B Arpa’s obvious problem and Mehrdad’s terrible solution (暴力枚举)

    题意:求定 n 个数,求有多少对数满足,ai^bi = x. 析:暴力枚举就行,n的复杂度. 代码如下: #pragma comment(linker, "/STACK:1024000000 ...