C语言中函数参数 ..._c语言函数入参为...-程序员宅基地

技术标签: C/C++语言  c语言  后端  开发语言  

  本文主要介绍va_start和va_end的使用及原理。

  在以前的一篇帖子Format MessageBox 详解中曾使用到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 是一个字符指针,可以理解为指向当前参数的一个指针,取参必须通过这个指针进行。
  <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,应该养成获取完参数表之后关闭指针的习惯。说白了,就是让我们的程序具有健壮性。通常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;
  }

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zhoenet/article/details/122122345

智能推荐

017、Python+fastapi,第一个Python项目走向第17步:ubuntu24.04 无界面服务器版下安装nvidia显卡驱动

新的ubuntu24.04正式版发布了,前段时间玩了下桌面版,感觉还行,先安装一个服务器无界面版本吧安装时有一个openssh选择安装,要不然就不能ssh远程,我就是没选,后来重新安装ssh。另外一个就是安装过程中静态ip设置下在etc/netplan 文件夹下,有一个yaml文件,我的是50-cloud-init.yaml,先用ip a看看network:ethernets:enp3s0:routes:version: 2。

不是阿里P8级大佬,岂能错过这篇MySQL运维内参?啃透涨薪so easy-程序员宅基地

文章浏览阅读176次。写在前面MySQL被设计为一个可移植的数据库,几乎在当前所有系统上都能运行,如Linux、Solaris、 FreeBSD、 Mac和Windows。尽管各平台在底层(如线程)实现方面都各有不同,但是MySQL基本上能保证在各平台上的物理体系结构的一致性。因此,用户应该能很好地理解MySQL数据库在所有这些平台上是如何运作的。由于工作的缘故,笔者的大部分时间需要与开发人员进行数据库方面的沟通,并对他们进行培训。不论他们是DBA,还是开发人员,似乎都对MySQL的体系结构了解得不够透彻。很多人喜欢把M_mysql运维内参

百度正用谷歌AlphaGo,解决一个比围棋更难的问题 | 300块GPU在燃烧-程序员宅基地

文章浏览阅读382次。晓查 发自 凹非寺量子位 报道 | 公众号 QbitAI9102年,人类依然不断回想起围棋技艺被AlphaGo所碾压的恐怖。却也有不以为然的声音:只会下棋的AI,再厉害..._alpha go训练用了多少个gpu

docker 容器 设置网络代理_docker export http_proxy-程序员宅基地

文章浏览阅读3.3k次。docker 容器 设置网络代理以/bin/bash 形式进入容器:【设置http 及https代理】,如下:export http_proxy=http://172.16.0.20:3128export https_proxy=https://172.16.0.20:3128要取消该设置:unsethttp_proxyunset https_proxy..._docker export http_proxy

linux之笔记_linux 0775十六進制-程序员宅基地

文章浏览阅读263次。授课环境: 结束程序运行: ctrl + c 共享目录(工作目录): /kyo /Videos 访问共享目录流程: 是否能连通服务器 ping 3.3.3.9 是否服务器开启共享 showmount -e 3.3.3.9 挂载共享目录到本地: _linux 0775十六進制

普通屏幕已过时?裸眼3D屏幕显示效果更胜一筹!

与普通屏幕中播放的视频相对,裸眼3D屏幕需要先将裸眼3D视频分成两部分,分别呈现在左右两个视窗上,因此后者需要更高的分辨率,以及更精细的图像处理能力,以此使裸眼3D屏幕的画面展示效果更加细腻,进而加深每个物体和场景的深度感和空间感,让每个驻足于此的观众惊叹于裸眼3D屏幕的震撼视觉效果。另外,裸眼3D屏幕的色彩表现,也比大多的普通屏幕更加丰富和鲜艳,能够展现出电影级别的画面质量,总而言之,裸眼3D屏幕比之普通屏幕的显示效果,有着巨大的优势,这也是使裸眼3D成为重要显示技术的重要原因!

随便推点

K210与STM32之间的通信_k210与stm32通信-程序员宅基地

文章浏览阅读5.1k次,点赞2次,收藏70次。K210与STM32之间使用串口进行通信_k210与stm32通信

OpenHarmony语言基础类库【@ohos.util.List (线性容器List)】

而网上有关鸿蒙的开发资料非常的少,假如你想学好鸿蒙的应用开发与系统底层开发。你可以参考这份资料,少走很多弯路,节省没必要的麻烦。由两位前阿里高级研发工程师联合打造的《鸿蒙NEXT星河版OpenHarmony开发文档》里面内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(Harmony NEXT)技术知识点。

[自学笔记] ESP32-C3 Micropython初次配置

2、本次测试了两款IDE,分别是"thonny-4.1.4.exe"和"uPyCraft-v1.0.exe"。Thonny支持中文及多语言。而uPyCraft-v1.0只支持英文语言。因此入门时选用了Thonny作为IDE。(注:1、测试过程中IDE正常连接ESP32C3简约版的虚拟串口。不受简约版无串口芯片的影响。

初识Electron,创建桌面应用

古有匈奴犯汉,晋室不纲,铁木夺宋,虏清入关,神舟陆沉二百年有余,中国之见灭于满清初非满人能灭之,能有之也因有汉奸以作虎怅,残同胞媚异种,始有吴三桂洪承畴,继有曾国藩袁世凯以为厉。今率堂堂之师,征讨汉贼袁氏筑共和之体,或免于我子子孙孙被异族奴役。---- 《讨汉贼袁世凯檄文》- DOMContentLoaded事件:此时浏览器已经完全加载了HTML文件,并且DOM树已经生成好了。- Load事件:此时浏览器已经将所有的资源都加载完毕,可以正确读取页面中的资源。补充知识:Electron 生命周期。

Xcode 15构建问题

将ENABLE_USER_SCRIPT_SANDBOXING设为“no”即可!

OpenVINO应用案例:部署YOLO模型到边缘计算摄像头_openvino yolo-程序员宅基地

文章浏览阅读2.8k次,点赞3次,收藏23次。一、实现路径通过OpenVINO部署YOLO模型到边缘计算摄像头,其实现路径为:训练(YOLO)->转换(OpenVINO)->部署运行(OpenNCC)。二、具体步骤1、训练YOLO模型1.1 安装环境依赖有关安装详情请参阅 https://github.com/AlexeyAB/darknet#requirements-for-windows-linux-and-macos 。1.2 编译训练工具git clone https://github.com/AlexeyAB/da_openvino yolo

推荐文章

热门文章

相关标签