va_list & va_start & va_arg & va_end

C/C++可变参数列表参数处理方法va_list、va_start()、va_copy()、va_arg()、va_end() C/C++可变参数列表的处理方法 阅读详情

           va_list 属于变量 而 va_start & va_arg & va_end  C语言中解决变参问题的一组宏。头文件来自stdarg.h。

查看linux系统源码方式我一般用locate stdarg.h,然后找到提示目录vi进去。源文件定义是:

在Mac 下追踪头文件也会发现如下宏定义:

typedef __darwin_va_list va_list;
typedef __builtin_va_list    __darwin_va_list;    /* va_list */

本质上都是__builtin_va_list   


    va_list是一个字符指针,可以理解为指向当前参数的一个指针,取参必须通过这个指针进行。


   <Step 1> 在调用参数表之前,应该定义一个 va_list类型的变量,以供后用(假设这个 va_list 类型变量被定义为ap);
   <Step 2> 然后对 ap进行初始化,让它指向可变参数表里面的第一个参数。这是通过 va_start 来实现的,其第一个参数是 ap本身,

                  第二个参数是在变参表前面紧挨着的一个变量;
   <Step 3> 然后是获取参数,调用 va_arg。它的第一个参数是ap,第二个参数是要获取的参数的指定类型,并返回这个指定类型的值,

                   同时把 ap 的位置指向变参表的下一个变量位置;
   <Step 4> 获取所有的参数之后,我们有必要将这个 ap指针关掉,以免发生危险,方法是调用 va_end。它是将输入的参数 ap 置为NULL,

                  应该养成获取完参数表之后关闭指针的习惯。

示例一:

void simple_va_fun(int i, ...)
{
    va_list arg_ptr;
    
    va_start(arg_ptr, i);
    int num1 = va_arg(arg_ptr, int);
    int num2 = va_arg(arg_ptr, int);

    va_end(arg_ptr);
    printf("%d %d %d /n", i, num1, num2);
    return;
}
示例二:

    // Quick Information Display  
    void show(id formatstring,...)  
    {  
        va_list arglist;  
        if (!formatstring) return;  
        va_start(arglist, formatstring);  
        id outstring = [[[NSString alloc] initWithFormat:formatstring arguments:arglist] autorelease];  
        va_end(arglist);  
          
        UIAlertView *av = [[[UIAlertView alloc] initWithTitle:@"LEAK DEMO" message:outstring delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] autorelease];  
        [av show];  
    }  
      
    - (void) intro  
    {  
        show(@"Run with Instruments using Leaks. Click a button to leak memory.%@\n",@"zyjzyj");  
    }  

示例三:

    #define showAlert(format, ...) myShowAlert(__LINE__, (char *)__FUNCTION__, format, ##__VA_ARGS__)  
      
    // Simple Alert Utility  
    void myShowAlert(int line, char *functname, id formatstring,...)  
    {  
          
        va_list arglist;  
        if (!formatstring) return;  
        va_start(arglist, formatstring);  
        id outstring = [[[NSString alloc] initWithFormat:formatstring arguments:arglist] autorelease];  
        va_end(arglist);  
          
        NSString *filename = [[NSString stringWithCString:__FILE__ encoding:NSUTF8StringEncoding] lastPathComponent];  
        NSString *debugInfo = [NSString stringWithFormat:@"%@:%d\n%s", filename, line, functname];  
          
        UIAlertView *av = [[[UIAlertView alloc] initWithTitle:outstring message:debugInfo delegate:nil cancelButtonTitle:@"OK"otherButtonTitles:nil] autorelease];  
        [av show];  
    }  
      
    - (void) rightAction: (id) sender  
    {  
        showAlert(@"You pressed the right button");  
    }  


      在C语言中,它们的详细定义如下:

1) va_list型变量:

#ifdef  _M_ALPHA
typedef struct {
        char *a0;       /* pointer to first homed integer argument */
        int offset;     /* byte offset of next parameter */
} va_list;
#else
typedef char *  va_list;
#endif

2)_INTSIZEOF 宏,获取类型占用的空间长度,最小占用长度为int的整数倍:

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

3)VA_START宏,获取可变参数列表的第一个参数的地址(ap是类型为va_list的指针,v是可变参数最左边的参数):

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

4)VA_ARG宏,获取可变参数的当前参数,返回指定类型并将指针指向下一参数(t参数描述了当前参数的类型):

#define va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

5)VA_END宏,清空va_list可变参数列表:

#define va_end(ap)      ( ap = (va_list)0 )

进一步解释:

va_list arg_ptr:定义一个指向个数可变的参数列表指针;

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)。

va_arg(arg_ptr, type):返回参数列表中指针arg_ptr所指的参数,返回类型为type,并使指针arg_ptr指向参数列表中下一个参数。

va_copy(dest, src):dest,src的类型都是va_list,va_copy()用于复制参数列表指针,将dest初始化为src。

va_end(arg_ptr):清空参数列表,并置参数指针arg_ptr无效。说明:指针arg_ptr被置无效后,可以通过调用

va_start ()、va_copy()恢复arg_ptr。每次调用va_start() / va_copy()后,必须得有相应的va_end()与之匹配。

参数指针可以在参数列表中随意地来回移动,但必须在va_start() … va_end()之内。

va函数的实现就是对参数指针的使用和控制。这里,移动指针使其指向下一个参数,那么移动指针时的偏移量是多少呢,

没有具体答案,因为这里涉及到内存对齐(alignment)问题,内存对齐跟具体 使用的硬件平台有密切关系,

比如大家熟知的32位x86平台规定所有的变量地址必须是4的倍数(sizeof(int) = 4)。

va机制中用宏_INTSIZEOF(n)来解决这个问题,没有这些宏,va的可移植性无从谈起。


参考内容来源:

初级篇:

http://blog.sina.com.cn/s/blog_590be5290100qhxr.html

http://justsee.iteye.com/blog/1637173

http://www.cnblogs.com/rainduck/archive/2010/11/10/1873417.html

http://www.cnblogs.com/margincc/archive/2011/03/29/2095057.html#undefined

进阶篇:

http://www.cnblogs.com/diyunpeng/archive/2010/01/09/1643201.html

http://blog.youkuaiyun.com/ritaday/article/details/6718353(强烈推荐)

http://www.cocoawithlove.com/2009/05/variable-argument-lists-in-cocoa.html (英文还可以的话,强烈推荐)

http://blog.youkuaiyun.com/skymingst/article/details/36872003 (转载的上篇英文,原文打不开连接的参考下)



gcc多平台va_list重载问题 刚刚解决了一个自认为十分诡异的BUG,其根本原因是自己的技术深度不够,没有考虑不同平台下gcc中内置变量的定义不同所造成的。 现象为Koala LINUX客户端在64位平台工作正常,在32位平台会出现core dump,对core文件进行分析,调用堆栈如下所示: #0 0x00322701 in vfprintf () from /lib/libc.so.6 #1 0x003475f0 阅读详情

相关推荐

我们来一起聊聊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中的定义:

认知 行动 坚持 9103

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

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

bigger_belief的博客 1万+

英飞凌AURIX™ TC3xx系列MCU的ISO 26262安全机制实战:从安全手册到代码集成的避坑指南

本文深入探讨英飞凌AURIX™ TC3xx系列MCU的ISO 26262安全机制实战应用,重点解析锁步核配置、ECC策略优化及SafeTlib库集成中的关键问题。通过代码示例和配置建议,帮助开发者实现ASIL D级别安全性,规避常见陷阱,提升汽车电子系统的功能安全合规性。

weixin_42558093的博客 405

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;amp;param1+ sizeof(param1) )...

3万+

MicroLogix1400编程(使用RSLogix 500 + RSLinx Classic Lite)

MicroLogix1400编程

noscallion的博客 1万+

3DGS实战笔记:从相机坐标系到屏幕像素,手把手推导高斯椭球的投影变换矩阵

本文详细解析了3D高斯散射(3DGS)技术中从相机坐标系到屏幕像素的几何变换过程,重点推导了高斯椭球的投影变换矩阵。通过视图变换、投影变换和视口变换的完整流程,结合雅可比矩阵处理协方差矩阵,实现了高效的三维重建与渲染。文章提供了Python代码示例,帮助开发者深入理解3DGS的核心几何变换机制。

weixin_28691741的博客 438

变长参数va_list va_start va_arg va_end

对于int printf(const char *format, ...);这种变长参数,需要使用va_list va_start va_end va_arg来访问参数。 下面是一个tutorialspoint 的一个使用demo,示范如何使用这几个接口 #include&lt;stdarg.h&gt; #include&lt;stdio.h&gt; int sum(int num_args, ...) { int val = 0, i; va_list ap; va_start(ap,

faxiang1230的专栏 4793

解析 RABAX during SAPGUI Logon 错误及其解决方案

登录用户关联了初始启动程序,该程序由于未处理的异常导致运行时错误。在 ST22 查看错误的程序名和错误行。修复初始程序代码中的逻辑问题。重新部署修复后的代码。示例代码:防止未处理的异常TRY." 模拟逻辑处理ENDTRY.此代码通过 TRY-CATCH 块捕获潜在错误,避免程序崩溃。是 SAP 系统中常见的运行时错误,其根源可能涉及多个方面,包括用户配置、系统状态、数据库连接和自定义开发等。通过结合 ST22、SM21 等诊断工具,以及完善的代码实践和系统监控,可以有效预防和解决此类问题。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1781

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

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

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

网络安全与黑客攻防常见设备:前置机、跳板机、堡垒机与肉鸡

前置机、跳板机、堡垒机和肉鸡,这些看似冷僻的技术名词,实则是网络安全与黑客攻防战中的关键角色。它们有的守护着企业的数字Pltform,保卫网络安全;有的则成为黑客的跳板,游走于灰色地带。

网络技术联盟站 963

Android AVB 分析(十六)5 个例子彻底理解 FEC(Reed-Solomon) 的工作原理

关于 FEC 是如何工作的,一直是我 Android OTA 讨论群中的未解话题,大家基本上都不清楚 Android 上面的 FEC 是如何工作的,为什么在 OTA 升级的最后阶段,FEC 的编码计算会消耗大量的 IO 资源,并持续很长时间。接下来的几篇,我会从一个程序员的角度,演示基于里德所罗门编码的 FEC 到底是如何工作的。

洛奇看世界 669

详细介绍关于宏va_list ,va_start ,va_arg ,va_end的使用

之前在查阅资料时一直没有找到一个完整的介绍这些宏的文章,故根据自己的理解整理了一下。va_list ,va_start ,va_arg ,va_end是C中stdarg.h头文件里面的宏,它们主要用于配合处理一组可变参数,这组可变参数的数量无需提前确定,用起来十分灵活。

zhibaishouhei927的博客 1323

Python 爬虫实战:arXiv 学术论文 PDF 批量下载(含反爬策略与文件命名规范)

arXiv 是全球最大的免费开放预印本论文平台之一,涵盖物理学、数学、计算机科学等多个学科领域。研究人员、学生和工程师常常需要批量下载论文 PDF 进行文献综述、构建机器学习数据集或进行文本挖掘研究。然而,手动逐篇下载论文效率低下,因此开发一个自动化批量下载工具显得尤为重要。

yansideyucsdn的博客 1817

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

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

春夜喜雨的专栏 1728

特征拼接(Feature Concatenation)技术全景解析

特征拼接是深度学习中的核心特征融合技术,通过在指定维度连接不同来源的特征张量,创造性地解决了多源、多尺度特征融合的关键挑战。这种简单却强大的操作已成为现代神经网络架构设计的基石。

浩瀚之水的专栏 1641

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

va_list,va_start,va_arg,va_copy和va_end的使用

va_list arg_ptr:定义一个指向个数可变的参数列表指针; va_start(arg_ptr, argN):使参数列表指针arg_ptr指向函数参数列表中的第一个可选参数,说明:argN是位于第一个可选参数之前的固定参数,(或者说,最后一个固定参数;…之前的一个参数),函数参数列表中参数在内存中的顺序与函数声明时的顺序是一致的。如果有一va函数的声明是void va_test(

garygeeker的专栏 2448

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

va_list 、va_start、 va_arg、 va_end ,vsnprintf使用说明

在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) ) va_arg宏,获取可变参数的当前参数,返回指定类型并将指针指向下一参数(mode参数描述了当前参数的类型): #d

惊鸿一瞥 1101

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

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

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

junxuezheng的博客 2219

va_start/va_arg/va_end/va_list

va_* 可变参数列表处理

Tyrower_rjx 1462

va_start、va_arg、va_end、va_list的使用

VA_LIST 是在C语言中解决变参问题的一组宏 他有这么几个成员: 1) va_list型变量: #ifdef  _M_ALPHAtypedef struct {        char *a0;       /* pointer to first homed integer argument */        int offset;     /* byte offset of next

cactusz的博客 397

va_list,va_start,va_arg,va_end可变参数

<!-- span {font-family:'Courier New'; font-size:10pt; color:#000000} .sc2 {color:#008000} .sc4 {color:#FF8000} .sc5 {font-weight:bold; color:#0000FF} .sc10 {font-weight:bold; co

paomadi的专栏 2692

va_list、va_start、va_arg、va_end宏的使用方法

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

老衣的专栏 1131

变长参数va_list, va_start, va_arg, va_end, va_copy的用法

#include        void va_start(va_list ap, last);        type va_arg(va_list ap, type);        void va_end(va_list ap);        void va_copy(va_list dest, va_list src);   1. 查看man里的定义,可知: va_lis

dihuasese88 1429

C语言va_list,va_start,va_arg,va_end解析

va_start、va_arg、va_end、va_list的使用 VA_LIST 是在C语言中解决变参问题的一组宏 他有这么几个成员: 1) va_list型变量: #ifdef  _M_ALPHA typedef struct {         char *a0;       /* pointer to first homed integer argume

深水幽蓝博客---改变现在,改变未来,因为有梦想,所以有坚持 543
上一篇: Cocoa error 3840
下一篇: Variable argument lists in Cocoa
skyming
博客等级 码龄15年 249粉丝 175原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值