可变参函数对变参的取值工具(va_start,va_arg,va_end)

我们来一起聊聊va_list、va_start、va_arg、va_end 在C/C++中, 经常会接触到变参, 也就是va(variable argument), 我们的printf函数就是这么做的。 搞过软件开发的人肯定知道, 几乎所有软件的日志函数, 都会采用变参。 下面, 我们来一起聊聊va_list、va_start、va_arg、va_end 看一下这些东东在VC++6.0中的定义: 阅读详情

本文主要介绍va_start,va_arg,va_end的使用及原理。在以前的一篇帖子www.cnblogs.com/hanyonglu/archive/2011/04/19/2020738.html详解中曾使用到va_start和va_end这两个宏,但对它们也只是泛泛的了解。

  介绍这两个宏之前先看一下C中传递函数的参数时的用法和原理:

1.在C中,当我们无法列出传递函数的所有实参的类型和数目时,可以用省略号指定参数表

void foo(…);
void foo(parm_list,…);
这种方式和我们以前认识的不大一样,但我们要记住这是C中一种传参的形式,在后面我们就会用到它。

2.函数参数的传递原理

  函数参数是以数据结构:栈的形式存取,从右至左入栈。

  首先是参数的内存存放格式:参数存放在内存的堆栈段中,在执行函数的时候,从最后一个开始入栈。因此栈底高地址,栈顶低地址,举个例子如下:
void func(int x, float y, char z);
  那么,调用函数的时候,实参 char z 先进栈,然后是 float y,最后是 int x,因此在内存中变量的存放次序是 x->y->z,因此,从理论上说,我们只要探测到任意一个变量的地址,并且知道其他变量的类型,通过指针移位运算,则总可以顺藤摸瓜找到其他的输入变量。
  下面是 stdarg.h 里面重要的几个宏定义如下:
typedef char* va_list;
void va_start ( va_list ap, prev_param ); /* ANSI version */
type va_arg ( va_list ap, type );
void va_end ( va_list ap );
va_list 是一个字符指针,可以理解为指向当前参数的一个指针,取参必须通过这个指针进行。
Step1:在调用参数表之前,定义一个 va_list 类型的变量,(假设va_list 类型变量被定义为ap);
Step2: 然后应该对ap 进行初始化,让它指向可变参数表里面的第一个参数,这是通过 va_start 来实现的,第一个参数是 ap 本身,第二个参数是在变参表前面紧挨着的一个变量,即“…”之前的那个参数;
Step3: 然后是获取参数,调用va_arg,它的第一个参数是ap,第二个参数是要获取的参数的指定类型,然后返回这个指定类型的值,并且把 ap 的位置指向变参表的下一个变量位置;
Step4: 获取所有的参数之后,我们有必要将这个 ap 指针关掉,以免发生危险,方法是调用 va_end,他是输入的参数 ap 置为 NULL,应该养成获取完参数表之后关闭指针的习惯。说白了,就是让我们的程序具有健壮性。通常va_start和va_end是成对出现。
例如 int max(int n, …); 其函数内部应该如此实现:

include <iostream.h> 
void fun(int a, ...) 
{ 
  int *temp = &a;
  temp++;
  for (int i = 0; i < a; ++i) 
  { 
    cout << *temp << endl; 
    temp++; 
  } 
}
int main() 
{ 
  int a = 1; 
  int b = 2; 
  int c = 3; 
  int d = 4; 
  fun(4, a, b, c, d); 
  system("pause"); 
  return 0; 
} 

Output:: 
1 
2 
3 
4

3:获取省略号指定的参数
  在函数体中声明一个va_list,然后用va_start函数来获取参数列表中的参数,使用完毕后调用va_end()结束。像这段代码: 
void TestFun(char* pszDest, int DestLen, const char* pszFormat, ...) 
{ 
va_list args; 
va_start(args, pszFormat); //一定要“...”之前的那个参数
_vsnprintf(pszDest, DestLen, pszFormat, args); 
va_end(args); 
}

4.演示如何使用参数个数可变的函数,采用ANSI标准形式 
#include 〈stdio.h〉 
#include 〈string.h〉 
#include 〈stdarg.h〉 

/*函数原型声明,至少需要一个确定的参数,注意括号内的省略号*/ 
int demo( char, ... ); 
void main( void ) 
{ 
   demo("DEMO", "This", "is", "a", "demo!", ""); 
} 

/*ANSI标准形式的声明方式,括号内的省略号表示可选参数*/ 
int demo( char msg, ... ) 
{ 
       /*定义保存函数参数的结构*/
   va_list argp; 
   int argno = 0; 
   char para; 
     /*argp指向传入的第一个可选参数,msg是最后一个确定的参数*/ 
   va_start( argp, msg ); 
   while (1) 
       { 
        para = va_arg( argp, char); 
           if ( strcmp( para, "") == 0 ) 
               break; 
           printf("Parameter #%d is: %s\n", argno, para); 
           argno++; 
} 
va_end( argp ); 
/*将argp置为NULL*/
return 0; 
}

以上是对va_start和va_end的介绍。

转载至:http://www.cnblogs.com/hanyonglu/archive/2011/05/07/2039916.html

我理解的C语言变参函数(va_arg,va_start,va_end)  va_arg va_start va_end 阅读详情

相关推荐

va_arg,va_start,va_end 使用学习

对于 可变参数的使用,脚本语言python,ruby使用起来很方便 不过C、C++也有利器,那就是va_arg之类函数。 笔者每次使用的时候,都要查msdn的文档, 所以这次把它记录下来。 方便以后的查询。 首先是对可变参数处理的函数有哪些,需要哪些头文件

php_boy的专栏 1651

变参函数的详细分析

我们利用printf函数来搞懂变参函数,我们知道printf函数的原型为int printf(const char *format, ...);其中...代表了变参,我们通过printf函数入手来确定固定参数,可变参数,最后引出变参函数。1.确定固定参数参数固定参数是一个char* 的指针,我们可以将它所指的内容直接打印出来#include int MyPrintf(const char *for

guoyongxu的博客 5667

stdarg.h中三个宏va_start ,va_arg和va_end的应用

1)首先在函数里定义一个va_list型的变量,这里是arg_ptr,这个变 量是指向参数的指针. 2)然后用va_start宏初始化变量arg_ptr,这个宏的第二个参数是第 一个可变参数的前一个参数,是一个固定的参数. 3)然后用va_arg返回可变的参数,并赋值给整数j. va_arg的第二个 参数是你要返回的参数的类型,这里是int型. 4)最后用va_end宏结束可变参数的获取.然后你就可以在函数里使

C语言 va_arg正确读取参数

c语言 va_arg使用

dhl11的博客 1159

屏幕取色值工具六种取值(pixel/HEX/HTML/RGB/CMYK/HSV)仅12K

屏幕取色值工具是一款很方便的屏幕取色器,方便拖动关闭,永在最前面,六种取值(pixel/HEX/HTML/RGB/CMYK/HSV)仅12K。

DexProtector内存态匿名段检测绕过与dex重组技术

Dex文件是Android应用的核心执行单元,其结构规范(如header_item、class_def_item、code_item)决定了运行时加载与解析的底层逻辑。DexProtector通过将dex数据拆解为多个无文件名、受保护的内存匿名段(如[anon:dp_header]、[anon:dp_code]),规避传统基于文件特征或标准加载路径的检测机制。该策略依赖Android mmap内存管理与ART虚拟机对dex结构的刚性要求,形成可被观测的布局规律。理解其内存态组织原理,结合权限/大小/命名/内

weixin_30855761的博客 688

DOM对象与jQuery对象的认识与区别

今天看JqueryAPI(<-点击可查看)的each()的时候,遇到了一个概念:就是DOM对象与jQuery对象。如下图,然后就查阅了资料了解了一下。 首先可以看两行代码,就知道DOM对象和jQuery对象了。 var domObj = document.getElementById("name"); //domObj则为DOM对象 var jQueryObj = $("#name"); //jQueryObj则为jQuery对象 通过获取元素的方式不同,分为...

sunshine_0880的博客 347

耕地质量评价软件实操指南:如何用Excel+ArcGIS一键生成土壤普查报告(附避坑技巧)

本文提供了一套融合Excel数据处理与ArcGIS空间分析的耕地质量评价实战工作流。详细讲解了从数据规范化预处理、高效数据桥接,到在ArcGIS中实现指标评分、综合指数计算与等级划分的全流程,旨在帮助土壤普查工作者大幅提升报告生成效率与准确性,并分享了关键的避坑技巧。

weixin_28455801的博客 489

Dart开发之——类

一 概述 本文介绍Dart中对象的模板:类,涉及一下知识点: 自定义类和构造方法 类中属性和实例方法及静态属性和方法 抽象类及抽象方法 类的继承 类的运算符重载 枚举类型 扩展类的功能——Mixin 二 自定义类和构造方法 2.1 说明 用class关键字来定义类 根据实际需求用于描述对象,定义属性信息(如年龄,性别等) 构造方法:定义一个初始化时已经有属性的对象(年龄,性别) 2.2 示例 自定义类及其赋值 class People { //年龄 late int age; //姓名

我的博客 443

pikachu靶场: 暴力破解第四关(token防爆破)

Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个 Token 同时将此 Token 返回给客户端。此外,Token 是有时效的,一段时间之后或下一次请求时用户需要重新验证。

X_shiguang的博客 1720

HarmonyOS NEXT 开发者预览版Beta招募应知测试

本次HarmonyOS NEXT 开发者预览版 Beta 招募活动为开发者预览版尝鲜升级,主要供开发者进行应用调测使用,除部分系统应用外,其他所有应用将被清除,因此在进行HarmonyOS NEXT 开发者预览版升级前,需进行数据备份。通过应知测试,并提交了参加HarmonyOS NEXT 开发者预览版招募 Beta 活动的报名信息,就会立刻审核通过并且收到新版本。手机在参加HarmonyOS NEXT 开发者预览版 Beta 招募活动前,需要对应机型升级到招募要求对应的基线版本,并预留内存空间。

长久公子的博客 8648

Dart可变参数,命名参数

void main() { for (int i = 0; i < 5; i++) { print('hello ${i + 1}'); } show_info("Tom"); show_info("Lucy", 20); show_info2("Cat"); show_info2("Mouse", age:10, sex:'femail'); } void show_info(String name, [int? age]) { if (age != null.

767

从入门到精通:激光器恒流驱动电路的设计与选型指南

本文深入解析了激光器恒流驱动电路的设计与选型。文章从基础电路原理讲起,对比了简易恒流源与高精度运放反馈方案的优劣,并重点阐述了如何为不同功率与精度要求的激光器项目选择合适的恒流驱动方案,强调了恒流源对于保障激光器稳定工作、防止热失控及延长寿命的核心作用。

grafana6viz的博客 711

可变参数:va_list(),va_start(),va_arg(),va_end() 详细解析

与 printf 类似,vsnprintf 可以根据格式化字符串中的占位符,将后续参数转换成对应的字符串并输出到缓冲区中,但是与 printf 不同的是,vsnprintf 可以指定输出的最大长度,以避免缓冲区溢出的问题。(1)format函数是一个可变参数函数,第一个参数pFmt是一个格式化字符串,后面的参数可以是任意数量的参数,用于填充格式化字符串中的占位符。va_start宏需要两个参数,分别是一个va_list类型的变量和可变参数的最后一个固定参数的地址。对变长参数列表进行访问和操作。

bigger_belief的博客 1万+

2025高教社数学建模国赛A题 - 烟幕干扰弹的投放策略(完整参考论文)

摘要:本研究基于模拟遗传退火算法优化无人机投放烟幕弹策略,建立三维运动学模型分析遮蔽效果。针对不同战术场景(单机单弹至多机多弹),构建以遮蔽时间最大化为目标的非线性优化模型。通过改进遗传算法求解最优参数组合,结果显示在给定条件下单枚烟幕弹对M1导弹的有效遮蔽时长可达1.4秒。研究为无人机协同干扰提供了高效解决方案,验证了智能算法在复杂战术决策中的适用性。关键词:烟幕干扰;无人机投弹;运动学建模;时序优化;遗传算法。

ProminentWu的博客 544

零基础教你学RDMA驱动开发:从入门到精通--第6章 内存管理与DMA映射​6.2 DMA地址转换:内核dma_map_single()与硬件IOVA(I/O虚拟地址)​

本文深入探讨RDMA驱动中DMA地址转换机制,重点分析内核dma_map_single()函数与硬件IOVA的作用。主要内容包括:1)DMA地址转换的必要性,解决CPU虚拟地址与HCA设备DMA地址的空间割裂问题;2)内核DMA映射机制实现原理,涵盖无IOMMU(直接物理地址映射)和有IOMMU(IOVA转换)两种场景;3)硬件IOVA的工作流程及其与RDMA内存注册的结合;4)RDMA驱动开发中的关键问题,如缓存一致性、映射方向错误、IOVA泄漏等;5)以mlx5驱动为例的实践分析。文章强调DMA地址转换

xiaoheshang_123的博客 239

C语言函数之可变参数原理:va_start、va_arg及va_end

说到C语言函数可变参数,我们最先想到的可能就是printf、scanf、printk了。在Linux-2.6.24.7内核源码里,printk函数原型如下: asmlinkageintprintk(constchar*fmt,...) asmlinkage表示通过堆栈传递参数。gcc编译器在汇编过程中调用c语言函数时传递参数有两种方法:一种是通过堆栈,另一种是通过寄存器。缺省时采用寄存器,假如你要在你的汇编过程中调用c语言函数,并且想通过堆栈传递参数,你定...

stephenbruce的博客 9254

virtuoso如何导出def?

在DEF Out界面,填写def name,library name以及cell name ,cell view既layout,把Output "Floating Shapes" into SPECIAL NETS Section勾上,OK即可。2)在要导出的layout界面选中PAD和prBoundary(shift+左键),快捷键C copy到空cell里,这时需要调整copy过来的object坐标,让两边prBoundary的坐标相同。我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧?

m0_61544122的博客 2304

【C++】变参函数va_start,va_arg,va_end介绍及实现方式

如果写过JS的话,就知道在JS中定义一个函数,就算输入的实参和形参不一致,也可以同过arguments获取参数上例输出1123在C/C++中其实也可以通过一些方式,获取实参中没有定义的多余参数,被称作变参函数。

. 1605

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

C/C++中va_start/va_arg/va_end函数源码文件位置及实现原理

在C/C++中,我们经常会用到可变参数的函数(比如printf/snprintf等),本篇笔记旨在讲解编译器借助va_start/va_arg/va_end这簇宏来实现可变参数函数的原理,并在文末给出简单的实例。 备注:本文的分析适用于Linux/Windows,其它操作系统平台的可变参数函数的实现原理大体相似。 1. 基础知识 如果想要真正理解可变...

banzhuangjushi的博客 3421

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

va_list/va_start/va_end/va_arg可变参数的使用

做日志打印或其它可变参数处理时,通常我们会想到使用va_list/va_start/va_end做可变参数的收集和处理。使用这种方式处理可变参数比较通用,同时适用于c与c++中。

春夜喜雨的专栏 1727

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

va_list 、va_start、 va_arg、 va_end 使用说明

在ANSI C中,这些宏的定义位于stdarg.h中: typedef char *va_list; va_start宏,获取可变参数列表的第一个参数的地址(list是类型为va_list的指针,param1是可变参数最左边的参数): #define va_start(list,param1)   ( list = (va_list)&amp;param1+ sizeof(param1) )...

3万+

【c++随笔08】可变参数——va_list、va_start、va_end、va_arg

原创作者:郑同学的笔记原创地址:https://zhengjunxue.blog.youkuaiyun.com/article/details/131690070qq技术交流群:921273910当你在编写 C++ 函数时,有时候你会需要处理可变数量的参数。C++ 中提供了 头文件,其中包含了用于处理可变参数的函数和宏。本教程将向你介绍如何使用 来编写可变参数的函数。

junxuezheng的博客 2219

va_list、va_start、va_arg、va_end宏的使用(转)

当你的函数的参数个数不确定时,就可以使用上述宏进行动态处理,这无疑为你的程序增加了灵活性。Example:CString AppendString(CString str1,...)//一个连接字符串的函数,参数个数可以动态变化{      LPCTSTR str=str1;//str需为指针类型,因为va_arg宏返回的是你的参数的指针,但是如果你的参数为int等简           

坚持,才是力量.老实做人,踏实做事. 3872

va_start、va_arg、va_end、va_copy 可变参函数

1、应用与原理 在C语言中,有时我们无法给出一个函数参数的列表,比如: int printf(const char *format, ...); int fprintf(FILE *stream, const char *format, ...); 这时我们使用到了可以变参数,也就是使用...代表0个或多个参数。 ...

aidixi4007的博客 612
上一篇: 不完全类型检测 “typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];”
下一篇: Boost库中的智能指针scoped_ptr,scoped_array
山农
博客等级 码龄10年 44粉丝 50原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值