va_list的原理及用法

2023-11-18

 

va_list原理及用法

分类: 编程2010-10-20 11:22 1426人阅读 评论(1) 收藏 举报

list编译器平台语言x86编程

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


下面是va_list的用法示例 

#include <stdarg.h> 

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宏,所以参数不能声明为寄存器变量,或作为函数或数组类型。


转载于:https://blog.51cto.com/6902621/1584907

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

va_list的原理及用法 的相关文章

  • C/C++语言实现WiFi(socket)数据收发(客户端和服务端)

    目录 客户端 client 服务端 server C C 实现TCP通信 接收WIFI数据 编程环境 VC 6 0 手机端 使用WiFi调试助手 提示 整个过程在局域网中进行 很多编程语言都可以实现socket通信 本博客将通过C C 实现
  • R语言学习笔记:分析学生的考试成绩

    孩子上初中时拿到过全年级一次考试所有科目的考试成绩表 正好可以用于R语言的统计分析学习 为了不泄漏孩子的姓名 就用学号代替了 感兴趣可以下载测试数据进行练习 num class chn math eng phy chem politics
  • 多线程系列之——事件内核对象

    所有内核对象里面事件内核对象是最简单的一个 它包括一个使用计数 还有两个布尔值 一个布尔值用来表示事件是手动重置事件还是自动重置事件 另一个布尔值表示当前是否处于触发状态 当一个手动重置事件被触发的时候 所有等待该事件的线程都能变成调度状态
  • 编写程序模拟完成动态分区存储管理方式的内存分配和回收。

    usr bin python coding utf 8 class Table object 空闲分区表 0 开始地址 1 长度 freeTable 占用分区表 0 程序名 1 开始地址 2 长度 useTable def init sel
  • 简析多级指针解引用

    转自 简析多级指针解引用 指针是C语言中公认的最为强大的语法要素 但同时也是最难理解的语法要素 它曾给程序员带来了无数麻烦和痛苦 以致于在C语言之后诞生的很多新兴 语言中我们再也难觅指针的身影了 下面是一个最简单的C语言指针的例子 int
  • GDAL多光谱与全色图像融合简单使用

    目录 简述 C 代码 效果对比 GDAL融合效果和原始多光谱波段对比 GDAL融合效果和原始全色波段对比 ARCGIS融合效果与原始全色和多光谱对比 GDAL融合效果与ArcGIS融合效果对比 简述 最近在GDAL的代码中看见了gdalpa
  • Lua和C++交互总结(很详细)

    出处 http blog csdn net shun fzll article details 39120965 一 lua堆栈 要理解lua和c 交互 首先要理解lua堆栈 简单来说 Lua和C c 语言通信的主要方法是一个无处不在的虚拟
  • dev-c++官网位置和源码/库位置

    1 http devpaks org 2 http www bloodshed net 3 http www bloodshed net dev 转载于 https www cnblogs com vilyLei articles 1812
  • LeetCode题目笔记——17.19消失的两个数字

    文章目录 题目描述 题目难度 困难 方法一 暴力 代码 代码优化 方法二 数学方法 代码 总结 题目描述 题目直达 题目难度 困难 方法一 暴力 虽然题目说你能在 O N 时间内只用 O 1 的空间找到它们吗 但是也没有限制我们不能用暴力
  • 值得学习与推荐的c/c++框架和函数库

    这几天不上班 翻翻Evernote中记录的一些笔记 刚好有时间把记录的一些好玩链接转载一下 这篇文章里提到的很多库都用过 尤其是图像处理相关库 尤其是opencv及cximage 当时做图像算法时 很多算法就是从上面找来 然后自己修改的 比
  • Dev-C++之开启装逼效果

    Dev C 是个不错的C IDE 在10年前 它是很不错 在现在 它是个以界面丑陋和调试像吃粑粑这两点著称 如下图 实在是丑到离谱 丑到无法忍受 可是没办法呀 人家CCF规定比赛用这个 你个小蒟蒻吵什么 我现在就来讲讲怎么把你的Dev C
  • C++学习笔记12:输入输出流实例整理(文本文件读写,二进制文件读写,一组数据的文件读写,随机访问文件实例

    这也太难记了555老阔疼 文件读写示例 include
  • Open3D(C++)实现建筑物点云立面和平面分割提取

    Open3D C 实现建筑物点云立面和平面分割提取 近年来 点云技术在城市规划 机器人地图构建等领域得到广泛应用 本篇文章将介绍如何利用Open3D C 库实现建筑物点云立面和平面分割提取 准备工作 首先需要编译安装Open3D库 本文使用
  • stat 函数解析

    stat 函数的简单使用 stat 函数是用来获取文件的各种属性的一个linux下的常用API函数 函数原型为int stat const char path struct stat buf stat定义如下 struct stat dev
  • 一个简单的参数帮助框架,c实现

    文章目录 具体实现如下 include
  • 虚函数不能声明为static

    虚函数申明为static报错 class Foo public Foo default static virtual Foo int main Foo foo return 0 main cpp 10 25 error member Foo
  • C++ 字符串比较------strcmp函数和strncmp函数

    strcmp 函数原型 int strcmp const char str1 const char str2 功能 strcmp函数会按照字典顺序逐个比较两个字符串的字符 直到遇到不同的字符或者遇到字符串结束符 0 返回值 该函数返回值如下
  • C 语言文件读取全指南:打开、读取、逐行输出

    C 语言中的文件读取 要从文件读取 可以使用 r 模式 FILE fptr 以读取模式打开文件 fptr fopen filename txt r 这将使 filename txt 打开以进行读取 在 C 中读取文件需要一点工作 坚持住 我
  • C++实现函数重载的原理

    一 函数重载的概念 C 中允许存在同名函数 但要求函数参数的类型 个数不同 这些同名函数就称为函数的重载 void func int a int b cout lt lt func int a int b lt lt endl void f
  • 在 OS X 上的 virtualenv 中安装 scrapy 加密时发生错误 [关闭]

    Closed 这个问题需要调试细节 help minimal reproducible example 目前不接受答案 我正在安装 scrapypip in virtualenv on OS X 10 11 当它安装密码学时 它说 buil

随机推荐

  • 如何使用CSS递归选择所有子元素?

    当元素是某个元素的子元素时 子选择器匹配 子选择器由两个或多个由 gt 分隔的选择器组成 也称为元素 gt 元素选择器 它选择特定父级的所有元素 语法如下 选择所有子元素 element gt element 如果子元素递归选择 则使用以下
  • Python_文件的代码格式

    导入模块 定义全局变量 定义类 定义函数 在代码的最下方 def main pass 根据 name 判断是否执行下方代码 if name main main
  • 图解十大经典机器学习算法入门

    通过本篇文章可以对机器学习的常用算法有个常识性的认识 没有代码 没有复杂的理论推导 就是图解一下 知道这些算法是什么 它们是怎么具体应用的 1 决策树 根据一些 feature 进行分类 每个节点提一个问题 通过判断 将数据分为两类 再继续
  • OPENCV手势识别抓取图片

    PENCV手势识别抓取图片 一位油管的小哥做的项目非常棒 照着写了一个 代码 注意 看好cvzone的版本 太新的版本中有个函数没有 如果找不到这个函数的时候请更换一下库的版本 import cv2 from cvzone HandTrac
  • RESETLOG之后数据文件丢失的RMAN恢复测试

    RESETLOG之后数据文件丢失的RMAN恢复测试 一 场景 在T0时间点做了RMAN全备 随后在T1时间点由于误操作将T0表truncate 在T2时间点通过RMAN的不完全恢复 将数据库恢复到T1时间点 truncate之前 reset
  • 苹果所有常用证书,appID,Provisioning Profiles配置说明及制作图文教程、

    概述 苹果的证书繁锁复杂 制作管理相当麻烦 今天决定重置一个游戏项目中的所有证书 做了这么多次还是感觉很纠结 索性直接记录下来 日后你我他查阅都方便 首先得描述一下各个证书的定位 作用 这样在制作的时候心中有谱 对整个流程的把握也会准确一些
  • cmake的aux_source_directory

    一 问题背景 在同一目录下面 有多个源文件的时候 这个时候你不能都往下面第三条命令里面一直手动添加cpp源文件 那工作效率多低啊 cmake minimum required VERSION 2 8 project main add exe
  • 网站虚拟主机是什么?(什么是虚拟主机空间)

    刚入行的新手用户肯定会接触一个叫虚拟主机的空间 特别是建站行业和个人用户使用的很多 不过很多新手用户对虚拟主机空间还是理解的不太明白 下面我们就来聊聊什么是网站虚拟主机空间 什么是虚拟主机 虚拟主机又称虚拟空间 网站空间 它是由单台物理服务
  • Hadoop学习:深入解析MapReduce的大数据魔力(二)

    Hadoop学习 深入解析MapReduce的大数据魔力 二 3 3 Shuffle 机制 3 3 1 Shuffle 机制 3 3 2 Partition 分区 3 3 3 Partition 分区案例实操 3 3 4 WritableC
  • odoo安装启动遇到的问题

    问题 在第一次加载odoo配置文件的时候 启动失败 方法 1 先检查odoo conf的内容 尤其是路径 options This is the password that allows database operations admin
  • 【前端面试】taro面试题总结

    Taro是一个开放式跨端跨框架解决方案 支持使用React Vue js Nerv等框架来开发小程序 H5 react Native等应用 特性 多端转换支持 可以转换到h5 任意app小程序平台 父子组件通信 父组件用import引入子组
  • Python 中的 sscanf() 函数

    文章目录 Python 中的 sscanf 功能 使用 re 库中的正则表达式 使用Neuron库 函数 sscanf 来自编程语言 C 和 C 虽然 Python 没有为此方法提供任何完全等效的方法或库 但可能有其他方法来执行此功能 这篇
  • Flutter依赖注入

    依赖注入 依赖注入 Dependency Injection 简称DI 是一种软件设计模式 它的主要目的是将对象之间的依赖关系解耦 使得代码更加可维护 可测试 可扩展 使得代码更易于维护和测试 在Flutter中 DI可以帮助我们管理应用程
  • 设置 Oracle 监听器密码(LISTENER) .

    设置 Oracle 监听器密码 LISTENER 监听器也有安全 Sure 在缺省的情况下 任意用户不需要使用任何密码即通过lsnrctl 工具对Oracle Listener进行操作或关闭 从 而造成任意新的会话都将无法建立连接 在Ora
  • C51流水灯 running water lamp

    include
  • 百度智能云 × 火星人丨厨电智能化,从动“手”到动“口”

    家电智能化时代已至 厨电智能化怎甘落后 火星人厨具股份有限公司 简称 火星人 是一家致力改善人们厨房环境 解决厨房油烟危害的高科技公司 2010年成立以来 火星人集成灶凭借核心技术 目前已在全国发展专卖店达一千七百多家 销售额每年快速增长
  • 区块链技术与应用环境部署day-02

    区块链技术与应用环境部署 关于作者 作者介绍 博客主页 作者主页 简介 云计算领域优质创作者 在校期间参与众多计算机相关的省赛 国赛 斩获系列荣誉 考取华为资深工程师 红帽工程师等系列认证 关注我 简历模板 学习资料 文档下载 技术支持 都
  • python sorted函数详解2023.9.11

    sorted函数详解 1 输入和输出 2 key传入函数 1 输入和输出 help sorted Help on built in function sorted in module builtins sorted iterable key
  • VisualBrush画刷

    VisualBrush派生于TileBrush TileBrush可以用来重复填充目标区域 若要使用图像进行绘制 请使用 ImageBrush 若要通过绘图绘制 请使用 DrawingBrush 若要通过 Visual 进行绘制 请使用 V
  • va_list的原理及用法

    va list原理及用法 分类 编程2010 10 20 11 22 1426人阅读 评论 1 收藏 举报 list编译器平台语言x86编程 VA LIST 是在C语言中解决变参问题的一组宏 变参问题是指参数的个数不定 可以是传入一个参数也