首页 > 其他分享 >通过一个实例了解 va_list

通过一个实例了解 va_list

时间:2023-08-04 22:00:43浏览次数:37  
标签:va VA 变参 list ap 实例 参数

VA_LIS 是在C语言中解决【变参问题】的一组宏,【变参问题】是指参数的个数不定,

可以传入一个参数也可以是多个;可变参数中的每个参数的类型可以不同,也可以相同;

可变参数的每个参数并没有实际的名称与之相对应,用起来是很灵活。

其中va_list( VA_LIST 是在C语言中解决变参问题的一组宏):va_list表示可变参数列表类型,实际上就是一个char指针fmt。

下面是va_list的用法示例

 1 #include <stdargs.h>
 2 #include <stdio.h>
 3 
 4 float retAve(int cnt, ...);
 5 
 6 int main()
 7 {
 8     printf("1~5's ave is %.1f", retAve(5, 1, 2, 3, 4, 5));
 9     return 0;
10 }
11 
12 float retAve(int cnt, ...)
13 {
14     valist ap;
15     int i = cnt;
16     float ret = 0;
17     va_start(ap, cnt);
18     
19     while(i--)
20     {
21         ret += va_arg(ap, int);
22     }
23     return ret/(float)cnt;
24 }

VA_LIST的用法:
(1)首先在函数里定义一具VA_LIST型的变量,这个变量是指向参数的指针;
(2)然后用VA_START宏初始化变量刚定义的VA_LIST变量;
(3)然后用VA_ARG返回可变的参数,VA_ARG的第二个参数是你要返回的参数的类型(如果函数有多个可变参数的,依次调用VA_ARG获取各个参数);
(4)最后用VA_END宏结束可变参数的获取。

上面是va_list的具体用法,下面讲解一下va_list各个语句含义(如上示例黑体部分)和va_list的实现。

va_list ap;   //定义一个 va_list 变量ap
va_start (ap,v);  //执行ap = ( va_list )&v + _INTSIZEOF(v),ap指向参数v之后的那个参数的地址,即ap指向第一个可变参数在堆栈的地址。
va_arg (ap,t)   //取出当前ap指针所指的值,并使ap指向下一个参数。ap+=sizeof (t类型),让ap指向下一个参数的地址。
                //然后返回ap- sizeof (t类型)的t类型指针,这正是第一个可变参数在堆栈里的地址。然后用取得这个地址的内容。
va_end (ap);  // 清空 va_list ap。

  

可变参数是由宏实现的,但是由于硬件平台的不同,编译器的不同,宏的定义也不相同,下面是VC6.0中x86平台的定义:

typedef char * va_list; // TC中定义为void*
#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) ) //为了满足需要内存对齐的系统
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) //ap指向第一个变参的位置,即将第一个变参的地址赋予ap
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //获取变参的具体内容,t为变参的类型,如有多个参数,则通过移动ap的指针来获得变参的地址,从而获得内容
#define va_end(ap) ( ap = (va_list)0 ) //清空va_list,即结束变参的获取

 

C语言的函数形参是从右向左压入堆栈的,以保证栈顶是第一个参数,而且x86平台内存分配顺序是从高地址到低地址。因此似函数AVEInt(int var1,intvar2,…,int varN)内存分配大致上是这样的:(可变参数在中间)

 

 

参考:《va_list原理及用法》

 

标签:va,VA,变参,list,ap,实例,参数
From: https://www.cnblogs.com/FBsharl/p/17607158.html

相关文章

  • JAVA执行Linux命令报错Cannot run program error=2 , No such file or directory
    JAVA执行Linux命令报错Cannotrunprogramerror=2,Nosuchfileordirectory酒香不怕巷深IP属地:河北2019.04.2214:00:00字数411阅读6,648JAVA使用ProcessBuilder运行Linux命令报错:startfailed:Cannotrunprogram"xxx"(indirectory"xx"):error=2,......
  • python中的exec()、eval()以及complie()
    1.eval函数函数的作用:计算指定表达式的值。也就是说它要执行的python代码只能是单个表达式(注意eval不支持任何形式的赋值操作),而不能是复杂的代码逻辑。eval(source,globals=None,locals=None,/)参数说明:source:必选参数,可以是字符串,也可以是一个任意的code(代码)对象实......
  • [maven]java.lang.NoSuchMethodError: org.apache.maven.model.validation.DefaultMod
    Maven异常环境idea版本:2020.1.3maven版本:3.8.5问题描述在idea中加入maven配置时,idea一直报出java.lang.NoSuchMethodError:org.apache.maven.model.validation.DefaultModelValidator异常异常信息1)Errorinjectingconstructor,java.lang.NoSuchMethodError:org.......
  • JVM零基础到高级实战之Java内存区域虚拟机栈
    前言JVM零基础到高级实战之Java内存区域虚拟机栈JVM内存模型之虚拟机栈虚拟机栈是什么?用于作用于方法执行的一块Java内存区域为什么要有虚拟机栈?每个方法在执行的同时都会创建一个栈帧(StackFramel)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至......
  • java word转pdf
    经过几天研究有以下方式:POI 格式问题(不考虑)docx4j 转换后格式问题(待定)aspose 收费(破解)(待定)spire.doc收费(不考虑)document4jwindows(不能跨平台)(不考虑)jacob windows(不能跨平台)(不考虑)最开始采用docx4j到最后结果发现格式有问题,表格中文可以换行,但是数字和字......
  • JavaScript基础05
    函数参数的校验/***@判断参数是否为数字类型*@参数,一个参数*@返回值,如果参数是数字类型返回true,否则返回false*/functionisNumber(num){​ //1.第一版,把条件拆开判断​ //判断num是否是什么数据类型 if(typeofnum!=='number'){  console.log('num不是......
  • 简简单单,带你学会使用Java线程池
    在前面几篇文章中,波哥给小伙伴们讲解了什么是线程,以及创建线程的几种方法。这就有小伙伴问了,我们工作中用得最多的是线程池,波哥你能不能再给我们讲一讲线程池呀?既然小伙伴们提出需求了,波哥我就得满足大家了,今天我就为小伙伴们讲一讲线程池! 一.线程池1.什么是线程池在面向对象编程......
  • 记一次JavaScript异或算法加密 , 异或加密
     公司业务代码constBase64=require('base-64')functionxorEncrypt(str,key){letresultconstlist=[]for(leti=0;i<str.length;i++){constcharCode=str.charCodeAt(i)^key.charCodeAt(i%key.length)list.push(String.......
  • java--并发容器 ConcurrentMap
    在JDK1.4以下只有Vector和Hashtable是线程安全的集合(也称并发容器,Collections.synchronized*系列也可以看作是线程安全的实现)。从JDK5开始增加了线程安全的Map接口ConcurrentMap和线程安全的队列BlockingQueue(尽管Queue也是同时期引入的新的集合,但是规范并没有规定一定是线程安全......
  • C# 转 Java
    代码级转换,目前唯一可用的方案是TangibleC#toJavaConverter。把编译后的IL转为bytecode再反编译也是一个思路,没有找到相关实现。转换难点并不是语法,语法用CodeDOM解析后重新生成Java就好了。真正的难点是库,Tangible提供了不少辅助函数,比如Split之类的。当然,任......