C/C++中使用可变参数

发表于:2014-10-15 09:46

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:ference    来源:51Testing软件测试网采编

#
DoNet
分享:
  可变参数即表示参数个数可以变化,可多可少,也表示参数的类型也可以变化,可以是int,double还可以是char*,类,结构体等等。可变参数是实现printf(),sprintf()等函数的关键之处,也可以用可变参数来对任意数量的数据进行求和,求平均值带来方便(不然就用数组或每种写个重载)。在C#中有专门的关键字parame,但在C,C++并没有类似的语法,不过幸好提供这方面的处理函数,本文将重点介绍如何使用这些函数。
  第一步 可变参数表示
  用三个点…来表示,查看printf()函数和scanf()函数的声明:
  int printf(const char *, ...);
  int scanf(const char *, ...);
  这三个点用在宏中就是变参宏(Variadic Macros),默认名称为__VA_ARGS__。如:
  #define WriteLine(...) { printf(__VA_ARGS__); putchar('\n');}
  再WriteLine("MoreWindows");
  考虑下printf()的返回值是表示输出的字节数。将上面宏改成:
  #define WriteLine (...) printf(__VA_ARGS__) + (putchar('\n') != EOF ? 1: 0);
  这样就可以得到WriteLine宏的返回值了,它将返回输出的字节数,包括最后的’\n’。如下例所示i和j都将输出12。
  int i = WriteLine("MoreWindows");
  WriteLine("%d", i);
  int j = printf("%s\n", "MoreWindows");
  WriteLine("%d", j);
  第二步 如何处理va_list类型
  函数内部对可变参数都用va_list及与它相关的三个宏来处理,这是实现变参参数的关键之处。
  在<stdarg.h>中可以找到va_list的定义:
  typedef char *  va_list;
  再介绍与它关系密切的三个宏要介绍下:va_start(),va_end()和va_arg()。
  同样在<stdarg.h>中可以找到这三个宏的定义:
  #define va_start(ap,v)  ( ap = (va_list)&v + _INTSIZEOF(v) )
  #define va_end(ap)      ( ap = (va_list)0 )
  #define va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
  其中用到的_INTSIZEOF宏定义如下:
  #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
  来分析这四个宏:
  va_end(ap)这个最简单,就是将指针置成NULL。
  va_start(ap,v)中ap = (va_list)&v + _INTSIZEOF(v)先是取v的地址,再加上_INTSIZEOF(v)。_INTSIZEOF(v)就有点小复杂了。( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )全是位操作,看起来有点麻烦,其实不然,非常简单的,就是取整到sizeof(int)。比如sizeof(int)为4,1,2,3,4就取4,5,6,7,8就取8。对x向n取整用C语言的算术表达就是((x+n-1)/n)*n,当n为2的幂时可以将最后二步运算换成位操作——将最低 n - 1个二进制位清 0就可以了。
  va_arg(ap,t)就是从ap中取出类型为t的数据,并将指针相应后移。如va_arg(ap, int)就表示取出一个int数据并将指针向移四个字节。
  因此在函数中先用va_start()得到变参的起始地址,再用va_arg()一个一个取值,最后再用va_end()收尾就可以解析可变参数了。
  第三步 vfprintf()函数和vsprintf()函数
  vfprintf()这个函数很重要,光从名字上看就知道它与经常使用的printf()函数有很大的关联。它有多个重载版本,这里讲解最常用的一种:
  函数原型
  int vfprintf(
  FILE *stream,
  const char *format,
  va_list argptr
  );
  第一个参数为一个FILE指针。FILE结构在C语言的读写文件必不可少。要对屏幕输出传入stdout。
  第二个参数指定输出的格式。
  第三个参数是va_list类型,这个少见,但其实就是一个char*表示可变参参数的起始地址。
21/212>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号