C++可变参数表基本内容探讨

开发 后端
C++可变参数表的使用方法及一些基本概念将会在这篇文章中详细介绍。大家可以通过对这里内容的解读充分掌握这方面的知识。

C++编程语言可以被看做C语言的一个升级版本。既然是基于C语言的一个编程语言,当然具有C语言中的所有功能。那么还有那些不同之处呢?其中就有一个不同于其它语言的特性,即其支持C++可变参数表,典型的函数如printf、scanf等可以接受数量不定的参数。如:

 

  1. printf ( "I love you" );   
  2. printf ( "%d", a );  
  3. printf ( "%d,%d", a, b );  

第一、二、三个printf分别接受1、2、3个参数,让我们看看printf函数的原型:

 

  1. int printf ( const char *format, ... );  

从函数原型可以看出,其除了接收一个固定的参数format以外,后面的参数用"…"表示。在C/C++语言中,"…"表示可以接受不定数量的参数,理论上来讲,可以是0或0以上的n个参数。

本文将对C++可变参数表的使用方法及C/C++支持可变参数表的深层机理进行探索。

C++可变参数表的用法

1、相关宏

标准C/C++包含头文件stdarg.h,该头文件中定义了如下三个宏:

 

  1. void va_start ( va_list arg_ptr, prev_param ); /* ANSI version */  
  2. type va_arg ( va_list arg_ptr, type );   
  3. void va_end ( va_list arg_ptr );  

在这些宏中,va就是variable argument(可变参数)的意思;arg_ptr是指向可变参数表的指针;prev_param则指可变参数表的前一个固定参数;type为可变参数的类型。va_list也是一个宏,其定义为typedef char * va_list,实质上是一char型指针。char型指针的特点是++、--操作对其作用的结果是增1和减1(因为sizeof(char)为1),与之不同的是int等其它类型指针的++、--操作对其作用的结果是增sizeof(type)或减sizeof(type),而且sizeof(type)大于1。

通过va_start宏我们可以取得C++可变参数表的首指针,这个宏的定义为:

 

  1. #define va_start ( ap, v ) ( ap = (va_list)&v + _INTSIZEOF(v) )  

显而易见,其含义为将最后那个固定参数的地址加上可变参数对其的偏移后赋值给ap,这样ap就是可变参数表的首地址。其中的_INTSIZEOF宏定义为:

 

  1. #define _INTSIZEOF(n) ((sizeof ( n ) + sizeof ( int ) - 1 )
     & ~( sizeof( int ) - 1 ) )  

va_arg宏的意思则指取出当前arg_ptr所指的可变参数并将ap指针指向下一可变参数,其原型为:

 

  1. #define va_arg(list, mode) ((mode *)(list =\  
  2. (char *) ((((int)list + (__builtin_alignof(mode)<=4?3:7)) &\  
  3. (__builtin_alignof(mode)<=4?-4:-8))+sizeof(mode))))[-1]  

 

对这个宏的具体含义我们将在后面深入讨论。

而va_end宏被用来结束C++可变参数表的获取,其定义为:

 

  1. #define va_end ( list )  

可以看出,va_end ( list )实际上被定义为空,没有任何真实对应的代码,用于代码对称,与va_start对应;另外,它还可能发挥代码的"自注释"作用。所谓代码的"自注释",指的是代码能自己注释自己。

下面我们以具体的例子来说明以上三个宏的使用方法。

2、一个简单的例子

 

  1. #include <stdarg.h> 
  2. /* 函数名:max  
  3. * 功能:返回n个整数中的最大值  
  4. * 参数:num:整数的个数 ...:num个输入的整数  
  5. * 返回值:求得的最大整数  
  6. */  
  7. int max ( int num, ... )  
  8. {  
  9. int m = -0x7FFFFFFF; /* 32系统中最小的整数 */  
  10. va_list ap;  
  11. va_start ( ap, num );  
  12. for ( int i0; i< num; i++ )  
  13. {  
  14. int t = va_arg (ap, int);  
  15. if ( t > m )  
  16. {  
  17. m = t;  
  18. }  
  19. }  
  20. va_end (ap);  
  21. return m;  
  22. }   
  23. /* 主函数调用max */  
  24. int main ( int argc, char* argv[] )  
  25. {   
  26. int n = max ( 5, 5, 6 ,3 ,8 ,5); /* 求5个整数中的最大值 */  
  27. cout << n;  
  28. return 0;  
  29. }  

 

函数max中首先定义了C++可变参数表指针ap,而后通过va_start ( ap, num )取得了参数表首地址(赋给了ap),其后的for循环则用来遍历可变参数表。这种遍历方式与我们在数据结构教材中经常看到的遍历方式是类似的。#t#

函数max看起来简洁明了,但是实际上printf的实现却远比这复杂。max函数之所以看起来简单,是因为:

(1) max函数可变参数表的长度是已知的,通过num参数传入;

(2) max函数可变参数表中参数的类型是已知的,都为int型。

而printf函数则没有这么幸运。首先,printf函数可变参数的个数不能轻易的得到,而可变参数的类型也不是固定的,需由格式字符串进行识别(由%f、%d、%s等确定),因此则涉及到C++可变参数表的更复杂应用。

责任编辑:曹凯 来源: 博客园
相关推荐

2010-02-05 10:08:55

C++名字空间

2010-02-06 13:58:13

C++ Bost库

2010-02-04 15:51:07

C++迭代器

2010-02-02 15:12:09

C++ explici

2010-02-05 13:35:19

C++虚析构函数

2010-01-04 15:21:37

Silverlight

2009-09-10 10:47:05

C# form

2010-01-28 15:33:37

Android程序架构

2010-04-22 09:36:56

Oracle数据字典

2010-02-25 15:49:05

WCF消息模式

2010-03-02 15:53:02

WCF服务合同

2017-10-25 06:50:27

数据科学数据数据分析

2010-02-25 17:51:04

WCF服务地址

2010-03-05 11:53:20

Python命名约定

2010-02-04 13:39:44

C++数组参数

2012-09-18 13:26:39

CC++

2010-03-02 17:55:37

WCF终结点地址

2010-03-03 15:26:54

Python编码规范

2010-02-25 17:04:54

WCF实例上下文

2010-04-12 12:52:54

WiMAX无线技术
点赞
收藏

51CTO技术栈公众号