关于va_list, va_start, va_arg, va_end

由于在C语言中没有函数重载,解决不定数目函数参数问题变得比较麻烦,即使采用C++,如果参数个数不能确定,也很难采用函数重载。对这种情况,提出了指针参数来解决问题。

**如printf()函数,其原型为:

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

它除了有一个参数format固定以外,后面跟的参数的个数和类型是可变的,例如我们可以有以下不同的调用方法: printf( "%d ",i); printf( "%s ",s); printf( "the number is %d ,string is:%s ", i, s);

如何实现其功能?

我们需要以下几个宏定义:

**(1)va_list

**定义了一个指针arg_ptr, 用于指示可选的参数.

**(2)va_start(arg_ptr, argN)

**使 参数列表指针arg_ptr指向函数参数列表中的第一个可选参数,argN是位于第一个可选参数之前的固定参数, 或者说最后一个固定参数.如有一va函数的声明是void va_test(char a, char b, char c, ...), 则它的固定参数依次是a,b,c, 最后一个固定参数argN为c, 因此就是va_start(arg_ptr, c).

**(3)va_arg(arg_ptr, type)

**返回参数列表中指针arg_ptr所指的参数, 返回类型为type. 并使指针arg_ptr指向参数列表中下一个参数.返回的是可选参数, 不包括固定参数.

**(4)va_end(arg_ptr)

**清空参数列表, 并置参数指针arg_ptr无效.

(注:va在这里是variable-argument(可变参数)的意思. 这些宏定义在stdarg.h中,所以用到可变参数的程序应该包含这个头文件)

 #include <iostream>
 #include <string>
 #include <iostream>
 using namespace std;
 #include <stdarg.h>
 void simple_va_fun(int i, ...)
 {
     va_list arg_ptr;       /// 定义可变参数指针
     va_start(arg_ptr, i);  /// i为最后一个固定参数
     int j = va_arg(arg_ptr, int); //返回第一个可变参数,类型为int
     char c = va_arg(arg_ptr, char); ///返回第二个可变参数,类型为char
     va_end(arg_ptr);  ///清空参数指针
     printf("%d %d %c", i, j, c);
     return;
 }
 ​
 int main()
 {
     simple_va_fun(100);
     cout << endl;
     simple_va_fun(100, 200);
     cout << endl;
     simple_va_fun(100, 200, 'a');
     cout << endl;
     system("pause");
     return 0;
 }

There are four parts needed:

va_list: stores the list of arguments

va_start: initializes the list

va_arg: returns the next argument in the list

va_end: cleans up the variable argument list

Whenever a function is declared to have an indeterminate number of arguments, in place of the last argument you should place an ellipsis (which looks like '...'), so, int a_function (int x, ...); would tell the compiler the function should accept however many arguments that the programmer uses, as long as it is equal to at least one, the one being the first, x

va_list is like any other variable. For example,

 va_list  a_list; 

va_start is a macro which accepts two arguments, a va_list and the name of the variable that directly precedes the ellipsis (...). So, in the function a_function, to initialize a_list with va_start, you would write va_start ( a_list, x );

va_arg takes a va_list and a variable type, and returns the next argument in the list in the form of whatever variable type it is told. It then moves down the list to the next argument. For example, va_arg ( a_list, double ) will return the next argument, assuming it exists, in the form of a double. The next time it is called, it will return the argument following the last returned number, if one exists.

To show how each of the parts works, take an example function:

 #include <cstdarg>
 #include <iostream>
 
 using namespace std;
 
 // this function will take the number of values to average
 // followed by all of the numbers to average
 double average ( int num, ... )
 {
   va_list arguments;                     // A place to store the list of arguments
   double sum = 0;
 
   va_start ( arguments, num );           // Initializing arguments to store all values after num
   for ( int x = 0; x < num; x++ )        // Loop until all numbers are added
     sum += va_arg ( arguments, double ); // Adds the next value in argument list to sum.
   va_end ( arguments );                  // Cleans up the list
 
   return sum / num;                      // Returns the average
 }
 int main()
 {
     // this computes the average of 13.2, 22.3 and 4.5 (3 indicates the number of values to average)
   cout<< average ( 3, 12.2, 22.3, 4.5 ) <<endl;
     // here it computes the average of the 5 values 3.3, 2.2, 1.1, 5.5 and 3.3
   cout<< average ( 5, 3.3, 2.2, 1.1, 5.5, 3.3 ) <<endl;
 }
 ​

C++中va_list, va_start, va_arg, va_end的基本用法的更多相关文章

  1. va_list/va_start/va_arg/va_end深入分析【转】

    转自:http://www.cnblogs.com/justinzhang/archive/2011/09/29/2195969.html va_list/va_start/va_arg/va_end ...

  2. C++省略参数(va_list va_start va_arg va_end)的简单应用

    原文参考自:http://www.cnblogs.com/hanyonglu/archive/2011/05/07/2039916.html #include <iostream> #in ...

  3. va_list/va_start/va_arg/va_end深入分析

    http://www.cnblogs.com/justinzhang/archive/2011/09/29/2195969.html

  4. va_start,va_arg,va_end的使用

    一.在C中,当我们无法列出传递函数的所有实参的类型和数目时,可以用省略号指定参数表. void fun(...); void fun(parm_list,...); #include <stdi ...

  5. va_list、va_start和va_end使用

    我们知道va_start,va_arg,va_end是在stdarg.h中被定义成宏的,由于1.硬件平台的不同 2.编译器的不同,所以定义的宏也有所不同. 在ANSI C中,这些宏的定义位于stdar ...

  6. va_start(),va_end()函数应用【转】

    转自:http://www.cnblogs.com/gogly/articles/2416833.html 原理解释: VA_LIST 是在C语言中解决变参问题的一组宏,在<stdarg.h&g ...

  7. va_start(),va_end()函数应用

    原理解释: VA_LIST 是在C语言中解决变参问题的一组宏,在<stdarg.h>头文件下. VA_LIST的用法:            (1)首先在函数里定义一具VA_LIST型的变 ...

  8. 深入C语言可变参数(va_arg,va_list,va_start,va_end,_INTSIZEOF)

    一.什么是可变参数 在C语言编程中有时会遇到一些参数个数可变的函数,例如printf(),scanf()函数,其函数原型为: int printf(const char* format,…),int ...

  9. OC可变參数的函数实现va_start、va_end、va_list的使用

    一.简单介绍 我们常常在编程的时候看见类似这种代码,如图1.1 图1.1 或者是这种可变參数,如图1.2 图1.2 二.基本知识介绍 在学习怎样写这样的格式的函数前,先简介几个经常使用的宏: 下面摘自 ...

  10. va_start和va_end使用详解

    本文主要介绍va_start和va_end的使用及原理. 介绍这两个宏之前先看一下C中传递函数的参数时的用法和原理: 1.在C中,当我们无法列出传递函数的所有实参的类型和数目时,可以用省略号指定参数表 ...

随机推荐

  1. image test

    png: jpeg: jpg: gif:

  2. QPushButton与Enter相链接

    ui->pushButton_login->setFocus(); // 设置默认焦点 ui->pushButton_login->setShortcut(QKeySequen ...

  3. windows 切换路径

  4. Web_Servlet四大域对象

    保存数据的对象作用于从大到小: ServletContext -- 保存数据到web项目中 Session(会话对象)  -- Request -- 保存当前请求(链),有转发就保存包括转发的数据 P ...

  5. DNS解析原理(www.baidu.com)

    QueryDns,py程序运行问题解决 关于远程访问数据库问题 这个我用NAVICAT或者是python程序连接都连不上他那个数据库(可能是数据库设定的权限没有开启?) 这个程序真的跑不起来,考虑自己 ...

  6. pycharm2019.3.1版本需要的JetBrains Runtime 11不支持windows 32位系统。

    提示信息显示安装pycharm2019.3.1版本需要的JetBrains Runtime 11不支持windows 32位系统. 2.更换pycharm社区版的安装版本 百度找到解决办法,参考文章& ...

  7. commons-lang3

    字符串的处理类(StringUtils) //判断是否为空(注:isBlank与isEmpty 区别) StringUtils.isBlank(null);StringUtils.isBlank(&q ...

  8. NO_PUBKEY 76F1A20FF987672F

    在ubuntu18.04上安装win时,执行sudo add-apt-repository 'deb https://dl.winehq.org/wine-builds/ubuntu/ bionic ...

  9. Microsoft SQL Server,错误: 3023

    对数据库的备份.文件操作(如 ALTER DATABASE ADD FILE)以及加密更改必须序列化.请在当前备份或文件操作完成后重新发出该语句.ALTER DATABASE 语句失败. (Micro ...

  10. 20181302编写myod.c 用myod XXX实现Linux下od -tx -tc XXX的功能

    MyOD 一.任务详情 1 复习c文件处理内容 2 编写myod.c 用myod XXX实现Linux下od -tx -tc XXX的功能 3. main与其他分开,制作静态库和动态库 4. 编写Ma ...