历史上的今天
返回首页

历史上的今天

今天是:2024年09月05日(星期四)

正在发生

2019年09月05日 | STM32基础知识4-va_list原理及用法

2019-09-05 来源:eefocus

VA_LIST 是在C语言中解决变参问题的一组宏,变参问题是指参数的个数不定,可以是传入一个参数也可以是多个;可变参数中的每个参数的类型可以不同,也可以相同;可变参数的每个参数并没有实际的名称与之相对应,用起来是很灵活。


下面是va_list的用法示例 :

#include  

int AveInt(int,...);

 void main()

{

       printf("%d/t",AveInt(2,2,3));

       printf("%d/t",AveInt(4,2,4,6,8));

       return;

}

int AveInt(int v,...)

{

       int ReturnValue=0;

       int i=v;

       va_list ap ;

       va_start(ap,v);

       while(i>0)

       {

              ReturnValue+=va_arg(ap,int) ;

              i--;

       }

       va_end(ap); 

       return ReturnValue/=v;

}

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的实现。


可变参数是由宏实现的,但是由于硬件平台的不同,编译器的不同,宏的定义也不相同,下面是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,int var2,...,int varN)内存分配大致上是这样的:(可变参数在中间)
栈区:
|栈顶             低地址
|第一个参数var1                  <-- &v
|第二个参数var2                  <-- va_start(ap,v)后ap指向地址       
|...
|函数的最后varN
|...
|函数的返回地址
|...
|栈底    高地址

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

va_end(ap) ; 清空va_list ap。

使用VA_LIST应该注意的问题: 

(1)因为va_start, va_arg, va_end等定义成宏,所以它显得很愚蠢,可变参数的类型和个数完全在该函数中由程序代码控制,它并不能智能地识别不同参数的个数和类型. 也就是说,你想实现智能识别可变参数的话是要通过在自己的程序里作判断来实现的.

(2)另外有一个问题,因为编译器对可变参数的函数的原型检查不够严格,对编程查错不利.不利于我们写出高质量的代码。


(3)由于参数的地址用于VA_START宏,所以参数不能声明为寄存器变量,或作为函数或数组类型。


本文参考如下文章:

http://hi.baidu.com/kang_liang/blog/item/168c9059a9a1ca2d2934f05f.html

http://fenge.bokee.com/195016.html

http://blog.csdn.net/homer1984/archive/2009/02/02/3859036.aspx


推荐阅读

史海拾趣

Delta Electronics Manufacturing Corp公司的发展小趣事

技术创新一直是Delta的核心竞争力。多年来,公司不断投入研发资源,推动技术创新和产品升级。Delta的工程师团队致力于电源技术的研发,成功推出了一系列具有领先技术水平的电源产品,如高效能转换器、智能电源管理系统等。这些产品不仅满足了市场的多样化需求,也推动了电源行业的技术进步。

Anytek Technology Corporation Ltd公司的发展小趣事

Anytek Technology Corporation Ltd自创立之初,便敏锐地捕捉到了车载电子产品的市场潜力。2003年,公司果断进军车载及行车记录仪领域,凭借前瞻性的市场洞察力和技术积累,迅速在行业内崭露头角。当时,随着汽车保有量的不断增加,行车记录仪作为保障行车安全、记录行车过程的重要设备,市场需求日益旺盛。Anytek凭借高品质的产品和专业的服务,赢得了广大消费者的信任和好评。

GREEGOO公司的发展小趣事
时钟信号线应远离一般信号线,避免并行走线以减少耦合干扰。
强盛电子(AEC)公司的发展小趣事

强盛电子(AEC)自成立以来,一直致力于电子技术的研发与创新。公司研发团队经过数年的努力,成功开发出一款具有颠覆性的新型芯片,这款芯片在性能上远超当时的同类产品,引起了市场的广泛关注。随着这款芯片的量产和上市,AEC的市场份额迅速扩大,成为行业内的佼佼者。

Horizon Electronics Enterprises Group公司的发展小趣事

随着技术产品的成功推出,Horizon开始积极拓展市场。公司首先在国内市场建立了完善的销售和服务网络,通过参加行业展会、举办技术研讨会等方式提升品牌知名度。同时,Horizon也意识到国际市场的巨大潜力,逐步在海外设立分支机构,将产品推向全球市场。通过持续的市场推广和优质的客户服务,Horizon的品牌影响力逐渐增强,成为电子行业内备受瞩目的新兴企业。

Dover Corporation公司的发展小趣事

Dover Corporation自上市以来,一直保持着持续盈利和向投资者发放红利的记录。公司凭借其强大的业务能力和稳健的财务状况,赢得了投资者的信任和支持。这一成绩的取得不仅彰显了Dover在业务运营方面的实力,也为其未来的发展奠定了坚实的基础。

请注意,以上故事框架仅为概述性质,具体细节和数据可能需要根据Dover Corporation的实际情况进行调整和补充。

问答坊 | AI 解惑

便携式串口调试助手,支持高波特率921600,大小仅5KB

[url=http://www.cinzy.com/soft/COMdbg.rar]便携串口调试助手 精品[/url] 串口调试软件中的一员,不同的是此版本纯API编写,运行高效稳定,只有5K,体系非常小巧,功能强大,非常值得收藏 5-20更新到0.2RC 修改几处内部逻辑使程序运行更快重新压缩使程 ...…

查看全部问答>

DSP与慢速设备接口的实现

DSP是一种高性能的数字信号处理器。由于其具有快速的计算能力和强大的信息处理能力,因此被广泛地应用到工业自动化、国防科研等领域中。与常规单片机相比,DSP的内部结构和时序发生了很大的变化。所以单片机适用的接口芯片,DSP并不一定适用。对于非常 ...…

查看全部问答>

哈工大遥控小汽车的设计

哈工大遥控小汽车的设计…

查看全部问答>

MPLAB ICD3问题请教

小弟又有问题了...在使用MPLAB ICD3调试的时候,会跳出此错误:查看ICD3 user‘s guide,有关提示如下:依照提示重新启动了目标板、ICD3等,还是提示错误,请各位高手指教,非常感谢!…

查看全部问答>

六路环行分配器(低速100khz以下)用哪种IC好

请问各位大侠六路环行分配器(低速100khz以下)用哪种IC好呢?…

查看全部问答>

最新 ADI的集成电源方案

ADP50xx系列电路,  4.5至15V的输入范围,集成开关型1.2A~4A的BUCK电路,以及LDO等。 是一款性能优良,功能完备的集成电源解决方案。 …

查看全部问答>

如何避免成为职场“橡皮人”?

    “橡皮人”在都市职场逐渐走红,他们“没有神经,没有痛感,没有效率,没有反应。整个人犹如橡皮做成的,不接受任何新生事物和意见、对批评表扬无所谓、没有耻辱和荣誉感的职场人们”。     初入职场,谁都曾豪情万丈踌 ...…

查看全部问答>

DC/DC的级联应用,容性负载是否传递

紧急求助:                  设计电源转换 由27V 转换为5V, 该DC/DC模块的容性负载时1000UF, 转换成5V 后,连接 5V到3.3V 的非隔离型DC/DC,  这个DC/DC的容性负载是30 ...…

查看全部问答>

使用检测电阻的开放无线电流感应电路[转]

Wireless Current Sense Circuit Floats with Sense Resistor 这里,Floats想了半天不知道怎么翻译好,现在用“开放式”来翻译它,不知道合适不合适。 这篇文章不错,提供了一种检测方法。 Introduction Measuring the current that flow ...…

查看全部问答>