【转】 可变参数表的用法 stdarg

[C/C++] 可变参数表(Variable Arguments)  C/C++支持可变长度的函数参数表,程序员可以通过指针运算并提领来获取函数的任意个参数。由于C/C++默认的__cedcl调用规范规定:函数参数的压栈和弹出操作都经由主调方进行,所以被调函数其实并不不需要知晓参数数量。为了使用这种可变参数函数调用,需要在参数表末尾添加三个句点形成的省略号“...” void g(int a,char* c,...); 省略号之前的逗号是可选的,并不影 阅读详情
 
【转】 可变参数表的用法 stdarg
2010年08月25日 星期三 上午 00:06
转载自 ___yiren___
最终编辑 jrckkyy
一、
printf ( "I love you" );
printf ( "%d", a );
printf ( "%d,%d", a, b );

  第一、二、三个printf分别接受1、2、3个参数,让我们看看printf函数的原型:

int printf ( const char *format, ... );

  从函数原型可以看出,其除了接收一个固定的参数format以外,后面的参数用"…"表示。在C/C++语言中,"…"表示可以接受不定数量的参数,理论上来讲,可以是0或0以上的n个参数。

  本文将对C/C++可变参数表的使用方法及C/C++支持可变参数表的深层机理进行探索。

  可变参数表的用法

  1、相关宏

  标准C/C++包含头文件stdarg.h,该头文件中定义了如下三个宏:

void va_start ( va_list arg_ptr, prev_param ); /* ANSI version */
type va_arg ( va_list arg_ptr, type );
void va_end ( va_list arg_ptr );

  在这些宏中,va就是variable argument(可变参数)的意思;arg_ptr是指向可变参数表的指针;prev_param则指可变参数表的前一个固定参数;type为可变参数的类型。va_list也是一个宏,其定义为typedef char * va_list,实质上是一char型指针。char型指针的特点是++、--操作对其作用的结果是增1和减1(因为sizeof(char)为1),与之不同的是int等其它类型指针的++、--操作对其作用的结果是增sizeof(type)或减sizeof(type),而且sizeof(type)大于1。

  通过va_start宏我们可以取得可变参数表的首指针,这个宏的定义为:

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

  显而易见,其含义为将最后那个固定参数的地址加上可变参数对其的偏移后赋值给ap,这样ap就是可变参数表的首地址。其中的_INTSIZEOF宏定义为:

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

  va_arg宏的意思则指取出当前arg_ptr所指的可变参数并将ap指针指向下一可变参数,其原型为:

#define va_arg(list, mode) ((mode *)(list =\
(char *) ((((int)list + (__builtin_alignof(mode)<=4?3:7)) &\
(__builtin_alignof(mode)<=4?-4:-8))+sizeof(mode))))[-1]

  对这个宏的具体含义我们将在后面深入讨论。

  而va_end宏被用来结束可变参数的获取,其定义为:

#define va_end ( list )

  可以看出,va_end ( list )实际上被定义为空,没有任何真实对应的代码,用于代码对称,与va_start对应;另外,它还可能发挥代码的"自注释"作用。所谓代码的"自注释",指的是代码能自己注释自己。

  下面我们以具体的例子来说明以上三个宏的使用方法。

  2、一个简单的例子

#include <stdarg.h>
/* 函数名:max
* 功能:返回n个整数中的最大值
* 参数:num:整数的个数 ...:num个输入的整数
* 返回值:求得的最大整数
*/
int max ( int num, ... )
{
 int m = -0x7FFFFFFF; /* 32系统中最小的整数 */
 va_list ap;
 va_start ( ap, num );
 for ( int i= 0; i< num; i++ )
 {
  int t = va_arg (ap, int);
  if ( t > m )
  {
   m = t;
  }
 }
 va_end (ap);
 return m;
}
/* 主函数调用max */
int main ( int argc, char* argv[] )
{
 int n = max ( 5, 5, 6 ,3 ,8 ,5); /* 求5个整数中的最大值 */
 cout << n;
 return 0;
}

  函数max中首先定义了可变参数表指针ap,而后通过va_start ( ap, num )取得了参数表首地址(赋给了ap),其后的for循环则用来遍历可变参数表。这种遍历方式与我们在数据结构教材中经常看到的遍历方式是类似的。

  函数max看起来简洁明了,但是实际上printf的实现却远比这复杂。max函数之所以看起来简单,是因为:

  (1) max函数可变参数表的长度是已知的,通过num参数传入;

  (2) max函数可变参数表中参数的类型是已知的,都为int型。

  而printf函数则没有这么幸运。首先,printf函数可变参数的个数不能轻易的得到,而可变参数的类型也不是固定的,需由格式字符串进行识别(由%f、%d、%s等确定),因此则涉及到可变参数表的更复杂应用。

二、写一个简单的可变参数的C函数
先看例子程序。该函数至少有一个整数参数,其后占位符…,表示后面参数的个数不定. 在这个例子里,所有的输入参数必须都是整数,函数的功能只是打印所有参数的值.
函数代码如下:
//示例代码1:可变参数函数的使用
#include "stdio.h"
#include "stdarg.h"
void simple_va_fun(int start, ...)
{
     va_list arg_ptr;
     int nArgValue =start;
     int nArgCout=0;      //可变参数的数目
     va_start(arg_ptr,start); //以固定参数的地址为起点确定变参的内存起始地址。
     do {
        ++nArgCout;
         printf("the %d th arg: %d\n",nArgCout,nArgValue);      //输出各参数的值
         nArgValue = va_arg(arg_ptr,int);                     //得到下一个可变参数的值
     } while(nArgValue != -1);                
     return;
}
int main(int argc, char* argv[])
{
     simple_va_fun(100,-1);
     simple_va_fun(100,200,-1);
     return 0;
}

下面解释一下这些代码

从这个函数的实现可以看到,我们使用可变参数应该有以下步骤:

⑴由于在程序中将用到以下这些宏:
     void va_start( va_list arg_ptr, prev_param );
     type va_arg( va_list arg_ptr, type );
     void va_end( va_list arg_ptr );
va在这里是variable-argument(可变参数)的意思.
这些宏定义在stdarg.h中,所以用到可变参数的程序应该包含这个头文件.

⑵函数里首先定义一个va_list型的变量,这里是arg_ptr,这个变量是存储参数地址的指针.因为得到参数的地址之后,再结合参数的类型,才能得到参数的值。

⑶然后用va_start宏初始化⑵中定义的变量arg_ptr,这个宏的第二个参数是可变参数列表的前一个参数,即最后一个固定参数.

⑷然后依次用va_arg宏使arg_ptr返回可变参数的地址,得到这个地址之后,结合参数的类型,就可以得到参数的值。

⑸设定结束条件,这里的条件就是判断参数值是否为-1。注意被调的函数在调用时是不知道可变参数的正确数目的,程序员必须自己在代码中指明结束条件。至于为什么它不会知道参数的数目,读者在看完这几个宏的内部实现机制后,自然就会明白。

(二)可变参数在编译器中的处理
我们知道va_start,va_arg,va_end是在stdarg.h中被定义成宏的, 由于1)硬件平台的不同 2)编译器的不同,所以定义的宏也有所不同,下面看一下VC++6.0中stdarg.h里的代码(文件的路径为VC安装目录下的\vc98\include\stdarg.h)
     typedef char *   va_list;
     #define _INTSIZEOF(n) ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
     #define va_start(ap,v)   ( ap = (va_list)&v + _INTSIZEOF(v) )
     #define va_arg(ap,t)     ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
     #define va_end(ap)       ( ap = (va_list)0 )

下面我们解释这些代码的含义:

1、首先把va_list被定义成char*,这是因为在我们目前所用的PC机上,字符指针类型可以用来存储内存单元地址。而在有的机器上va_list是被定义成void*的

2、定义_INTSIZEOF(n)主要是为了某些需要内存的对齐的系统.这个宏的目的是为了得到最后一个固定参数的实际内存大小。在我的机器上直接用sizeof运算符来代替,对程序的运行结构也没有影响。(后文将看到我自己的实现)。

3、va_start的定义为 &v+_INTSIZEOF(v) ,这里&v是最后一个固定参数的起始地址,再加上其实际占用大小后,就得到了第一个可变参数的起始内存地址。所以我们运行va_start(ap, v)以后,ap指向第一个可变参数在的内存地址,有了这个地址,以后的事情就简单了。

这里要知道两个事情:
     ⑴在intel+windows的机器上,函数栈的方向是向下的,栈顶指针的内存地址低于栈底指针,所以先进栈的数据是存放在内存的高地址处。
     (2)在VC等绝大多数C编译器中,默认情况下,参数进栈的顺序是由右向左的,因此,参数进栈以后的内存模型如下图所示:最后一个固定参数的地址位于第一个可变参数之下,并且是连续存储的。
|--------------------------|
|   最后一个可变参数              |    ->高内存地址处
|--------------------------|
|--------------------------|
|   第N个可变参数               |      ->va_arg(arg_ptr,int)后arg_ptr所指的地方,
|                                |      即第N个可变参数的地址。
|--------------- |     
|--------------------------|
|   第一个可变参数                |      ->va_start(arg_ptr,start)后arg_ptr所指的地方
|                                |      即第一个可变参数的地址
|--------------- |     
|------------------------ --|
|                                |
|   最后一个固定参数              |     -> start的起始地址
|-------------- -|        .................
|-------------------------- |
|                                |  
|--------------- |   -> 低内存地址处

(4) va_arg():有了va_start的良好基础,我们取得了第一个可变参数的地址,在va_arg()里的任务就是根据指定的参数类型取得本参数的值,并且把指针调到下一个参数的起始地址。
因此,现在再来看va_arg()的实现就应该心中有数了:
     #define va_arg(ap,t)     ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
这个宏做了两个事情,
    ①用用户输入的类型名对参数地址进行强制类型转换,得到用户所需要的值
    ②计算出本参数的实际大小,将指针调到本参数的结尾,也就是下一个参数的首地址,以便后续处理。

(5)va_end宏的解释:x86平台定义为ap=(char*)0;使ap不再 指向堆栈,而是跟NULL一样.有些直接定义为((void*)0),这样编译器不会为va_end产生代码,例如gcc在linux的x86平台就是这样定义的. 在这里大家要注意一个问题:由于参数的地址用于va_start宏,所以参数不能声明为寄存器变量或作为函数或数组类型. 关于va_start, va_arg, va_end的描述就是这些了,我们要注意的 是不同的操作系统和硬件平台的定义有些不同,但原理却是相似的.

(三)可变参数在编程中要注意的问题
因为va_start, va_arg, va_end等定义成宏,所以它显得很愚蠢, 可变参数的类型和个数完全在该函数中由程序代码控制,它并不能智能 地识别不同参数的个数和类型. 有人会问:那么printf中不是实现了智能识别参数吗?那是因为函数 printf是从固定参数format字符串来分析出参数的类型,再调用va_arg 的来获取可变参数的.也就是说,你想实现智能识别可变参数的话是要通过在自己的程序里作判断来实现的. 例如,在C的经典教材《the c programming language》的7.3节中就给出了一个printf的可能实现方式,由于篇幅原因这里不再叙述。

(四)小结:
1、标准C库的中的三个宏的作用只是用来确定可变参数列表中每个参数的内存地址,编译器是不知道参数的实际数目的。
2、在实际应用的代码中,程序员必须自己考虑确定参数数目的办法,如
⑴在固定参数中设标志-- printf函数就是用这个办法。后面也有例子。
⑵在预先设定一个特殊的结束标记,就是说多输入一个可变参数,调用时要将最后一个可变参数的值设置成这个特殊的值,在函数体中根据这个值判断是否达到参数的结尾。本文前面的代码就是采用这个办法.
无论采用哪种办法,程序员都应该在文档中告诉调用者自己的约定。
3、实现可变参数的要点就是想办法取得每个参数的地址,取得地址的办法由以下几个因素决定:
①函数栈的生长方向
②参数的入栈顺序
③CPU的对齐方式
④内存地址的表达方式
结合源代码,我们可以看出va_list的实现是由④决定的,_INTSIZEOF(n)的引入则是由③决定的,他和①②又一起决定了va_start的实现,最后va_end的存在则是良好编程风格的体现,将不再使用的指针设为NULL,这样可以防止以后的误操作。
4、取得地址后,再结合参数的类型,程序员就可以正确的处理参数了。理解了以上要点,相信稍有经验的读者就可以写出适合于自己机器的实现来。下面就是一个例子

(五)扩展--自己实现简单的可变参数的函数。
下面是一个简单的printf函数的实现,参考了<The C Programming Language>中的156页的例子,读者可以结合书上的代码与本文参照。
#include "stdio.h"
#include "stdlib.h"
void myprintf(char* fmt, ...)         //一个简单的类似于printf的实现,//参数必须都是int 类型
{
     char* pArg=NULL;                //等价于原来的va_list
     char c;
     pArg = (char*) &fmt;     //注意不要写成p = fmt !!因为这里要对//参数取址,而不是取值
     pArg += sizeof(fmt);          //等价于原来的va_start          
    do
     {
         c =*fmt;
         if (c != ’%’)
         {
             putchar(c);             //照原样输出字符
         }
         else
{
//按格式字符输出数据
             switch(*++fmt)
{
             case ’d’:
                 printf("%d",*((int*)pArg));           
                 break;
             case ’x’:
                 printf("%#x",*((int*)pArg));
                 break;
             default:
                 break;
             }
             pArg += sizeof(int);                //等价于原来的va_arg
         }
         ++fmt;
     }while (*fmt != ’\0’);
     pArg = NULL;                                //等价于va_end
     return; }
int main(int argc, char* argv[])
{
     int i = 1234;
     int j = 5678;
     myprintf("the first test:i=%d\n",i,j);
     myprintf("the secend test:i=%d; %x;j=%d;\n",i,0xabcd,j);
     system("pause");
     return 0;
}
在intel+win2k+vc6的机器执行结果如下:
the first test:i=1234
the secend test:i=1234; 0xabcd;j=5678;


【PyBind11+anaconda+opencv+windows11+cmake+wsl+vscode】从入门到跑通。构建基于opencv c++的python package 如何安装请详见上文 【PyBind11+anaconda+opencv+windows11+cmake+wsl+vscode】从入门到跑通。构建基于opencv c++的python接口_子韵如初的博客-优快云博客w不需要安装啥x11 、 xming直接mobxterm可以搞定点击右上角的X server打开可视化服务器然后 apt install x11-apps -yxclock 搞定从mobxterm可以看到display的端口X11显示可视化的原理是就是通过X协议,类似于http对linux于w 阅读详情

相关推荐

平衡电桥在高压绝缘检测中的动态切换策略与误差优化

本文深入探讨了平衡电桥在高压绝缘检测中的动态切换策略与误差优化方法。通过分析四种基本切换模式及智能切换时序设计,显著提升检测精度与范围。结合电阻选型黄金法则和软件补偿技术,有效降低测量误差,为电动汽车电池管理系统提供可靠的安全保障。

weixin_30275415的博客 472

C stdarg.h的使用

参考: stdarg.h:https://zh.wikipedia.org/wiki/Stdarg.h stdarg.h:http://baike.baidu.com/view/3373010.htm linux环境下可以使用man手册:man stdarg ##############################################################

u012005313的专栏 1万+

【操作系统】实验楼操作系统实验三——系统调用

操作系统实验3——系统调用 环境配置 ​ 首先同样是配置环境 cd /home/shiyanlou/oslab tar -zxvf hit-oslab-linux-20110823.tar.gz -C /home/shiyanlou 实验步骤 添加函数声明 cd ~/oslab/linux-0.11/include/linux gedit sys.h //添加内容: extern int sys_whoami(); extern int sys_iam(); fn_ptr_sys_call_table

qq_46612803的博客 6357

【C语言】可变参数 stdarg.h

stdarg.h头文件中包含的函数为编程人员提供了访问可变参数的可移植方式,是fprintf和vfprintf等函数需要的。 因为C没有限制参数的传入方式,一般认为是不可移植的。传统的C中使用varargs.h来提高移植性,标准C使用stdarg.h 其中包含的宏: va_list:声名局部状态变量,如ap,用于遍历参数 va_start:初始化上面的状态变量ap,后面才可以使用va_arg和va...

zhoudawei的专栏 1177

翁恺-C语言程序设计 PTA习题集

代码练习题

qq_46085472的博客 7640

dq轴坐标系下的电路方程

dq轴坐标系下的电路方程 dq轴坐标系是一种常见的电路方程,但是再dq轴坐标系下电路元件的电压电流dq轴存在一定的耦合,本文针对三相电路推导了dq轴坐标系下的电路电路方程进行一个推导,首先先列出来派克变换的公式 派克变换 [AdAqA0]=23[cos⁡(θ)cos⁡(θ−2π/3)cos⁡(θ+2π/3)−sin⁡(θ)−sin⁡(θ−2π/3)−sin⁡(θ+2π/3)1/21/21/2][AaAbAc]\left[\begin{array}{c}A_d\\A_q\\A_0 \end{array}\ri

Mr.Young的博客 1万+

可变参数表的用法 stdarg

2010年08月25日 星期三 上午 00:06 转载自 ___yiren___ 最终编辑 jrckkyy 一、 printf ( "I love you" ); printf ( "%d", a ); printf ( "%d,%d", a, b );   第一、二、三个printf分别接受1、2、3个参数,让我们看看prin

技术斋 896

ArchLinux下用Wine运行钉钉全攻略:从字体配置到中文输入法避坑

本文详细介绍了在ArchLinux系统上使用Wine运行钉钉的完整配置流程。从最新的WoW64架构环境准备、中文字体配置与DPI优化,到钉钉安装、关键系统库替换,再到解决中文输入法失效等核心难题,提供了实战避坑指南。旨在帮助Linux用户在企业办公场景下,获得接近原生的稳定使用体验。

alice7model的博客 588

【Linux102】12-include/stdarg.h

Linux102系列会详细讲解Linux0.11版本中的102个文件,本文讲解linux0.11的第11个文件include/stdarg.h的文件源码。1.stdarg的主要作用stdarg.h是C 语言标准库中用于处理可变参数函数的头文件,核心作用是提供一套宏定义,让函数能够接收数量和类型不确定的参数(如 printf(const char *fmt, ...) 中的 ...)。

965

手把手教你解决Realsense D455在ROS下IMU数据不输出的问题(附固件降级指南)

本文详细解析了Realsense D455在ROS环境下IMU数据不输出的问题,提供了固件降级和ROS配置的完整解决方案。通过版本兼容性分析和实战操作指南,帮助开发者快速恢复IMU数据流,优化机器人开发体验。

weixin_42531494的博客 371

PMP--二模--解题--161-170

A:邀请团队成员在下一次回顾中分享经验。B:请求发起人增加具有所需经验的团队成员。C:在团队内计划知识共享会议。D:请求发起人为团队提供培训课程。A。

stqer的博客 1268

stdarg c语言,c语言基于stdarg.h的可变参数函数的用法

C语言编程中有时会遇到一些参数个数可变的函数,本文详细讲解了可变参数函数的实现原理,分享给大家在开始学习C语言的函数的时候,我们就知道函数的参数个数应该是在函数声明的时候就指定的,这一点我们没有任何疑问。但是不知道大家有没有注意到我们的printf()函数,他的函数参数理论上并不是确定的,而是随着匹配字符串中的格式控制符的个数控制的。其实当时也没有注意到这一点,到是最近,偶然间看到了 《嗨翻C语言...

weixin_32299949的博客 142

【BlueDroid】蓝牙音乐协议分析之A2DP和AVRCP连接流程(超详细)

AVCTP协议描述了蓝牙设备间Audio/Video的控制信号交换的格式和机制,他是一个总体的协议,具体的控制信息由其指定的协议(AVRCP)实现,AVCTP协议本身只指定控制Command和Response的总体的格式;这个过程中对应了Event中的btavrcp_play_status_changed_callback和btavrcp_play_position_changed_callback;上述为AVCTP-Control建立L2CAP连接的Command,对应H4的Sent (0x00);

风云说通信 7313

stdarg.h——用于函数接受可变参数

stdarg.h——用于函数接受可变参数

一路前行的专栏 1045

jre9下载 jdk9

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

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

可变参数列表,stdarg

所谓“可变参数列表”就是指函数的形参的数目和类型是不确定的。printf函数就是一个可变参数的函数,第一个参数是格式化字符串,后面可以跟任意数目的参数。而我们平时使用的函数,其参数的数目和类型都是固定的,一旦声明,无法改变。 1.计算一系列值的平均值 (注意:这些值不是保存在数组中的,而是在参数中显示的传递) ​float average( int n_values, int v1, int

qq_40395404的博客 246

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

stdarg.h

现在我们要说C语言一个强大的功能,它允许程序员自己定义可接受一个可变参数列表的函数。那么要咱们自己编写一个可接受一个可变参数列表的函数,就得用到头文件starg.h。

梵高先生的专栏 1472

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

stdarg Macro 关于可变参数

 #includestdio.h>#includestdarg.h>double average(int val,...)...{  va_list var_arg;  int count;  double sum=0.0;  /** *//**prepare to visit variable arguments**/  va_start(var_arg,val);    /** *//

HelloDan的专栏 892

可变参数列表_stdarg宏

用于实现可变参数列表的-stdarg具有非常神奇的用途

微风 607

可变参数函数:stdarg.h与printf原理

摘要: 本文深入解析C语言中的可变参数函数,重点介绍stdarg.h头文件的宏(va_list、va_start、va_arg、va_end)及其工作原理。通过printf函数的实现示例,展示如何利用格式字符串安全处理可变参数,并分析栈内存布局。文章还指出使用可变参数时的常见风险(如类型不匹配)和最佳实践,对比了性能开销,建议在性能敏感场景考虑替代方案。最后强调遵循标准规范的重要性,并推荐扩展阅读资源。

always_TT的博客 325

FreeRTOS打印函数终极指南:printf-stdarg.c可变参数输出实现详解

FreeRTOS作为嵌入式系统中广泛使用的实时操作系统,其**printf-stdarg.c可变参数输出实现**为开发者提供了强大的调试和日志输出能力。这个轻量级的printf实现专门为资源受限的嵌入式环境设计,支持多种格式化输出功能,是嵌入式开发中不可或缺的工具。 ## 🎯 什么是printf-stdarg.c? **printf-stdarg.c**是FreeRTOS中一个轻量级的格式化

gitblog_00314的博客 1107

C语言可变参数(stdarg.h包含)详解

该 宏 接受 一个 va_ list 类型 的 变量: va_ end( ap);因为 va_ arg() 不提 供 退回 之前 参数 的 方法, 所以 有 必要 保存 va_ list 类型 变量 的 副本。该 宏 接受 两个 va_ list 类型 的 变量 作为 参数, 它 把 第 2 个 参数 拷贝 给 第 1 个 参数。last是可变参数…接下来,声明 在 stdarg. h 中的 va_ list 类型 代表 一种 用于 储存 形 参 对应 的 形 参 列表 中 省略号 部分 的 数据 对象。

m0_52517713的博客 831

【c语言】可变长参数表,即函数的参数的数量可改变,使用stdarg.h头文件

c语言的函数没有重载,可以使用两种方式实现重载功能1.宏定义2.可变参数表,使用stdarg.h头文件本文介绍可变参数表的使用通过stdarg.h中的4个宏定义实现可变长参数一般只要看到第一个示例就可以了。第二个示例,是出自于祖师爷编写的书籍,如果研究一下,可以加深理解。

weiweiliude2的专栏 660

stdarg的用法(可变参数的用法)

stdarg宏: 可变参数列表是通过宏来实现的,这些宏定义于stdarg.h头文件,它是标准库的一部分。 这个头文件声明的一个va_list的类型,和三个宏va_start,va_arg,va_end。我们可以生明一个va_list类型的变量,配合三个宏使用。 va_start(arg, last have name arg); 初始化之后,arg将指向第一个无名参数。 va_arg(ar

crazy_koala的博客 651

C 标准库 <stdarg.h>与函数可变参数

stdarg.h 头文件定义了一个变量类型 va_list 和三个宏,这三个宏可用于在参数个数未知(即参数个数可变)时获取函数中的参数。之前在讲C语言可变参数的时候用到了这个(C语言变参数函数详解)。 可变参数的函数通在参数列表的末尾是使用省略号(,…)定义的。 库变量 下面是头文件 stdarg.h 中定义的变量类型: 序号 变量 & 描述 1 va_list 这是一个适用于 va_start()、va_arg() 和 va_end() 这三个宏存储信息的类型。 库宏 下面是头

qq_41854911的博客 287

stdarg c语言,stdarg的用法(可变参数的用法)

stdarg宏:可变参数列表是通过宏来实现的,这些宏定义于stdarg.h头文件,它是标准库的一部分。这个头文件声明的一个va_list的类型,和三个宏va_start,va_arg,va_end。我们可以生明一个va_list类型的变量,配合三个宏使用。va_start(arg, last have name arg);初始化之后,arg将指向第一个无名参数。va_arg(arg, next a...

weixin_34870207的博客 321

C语言函数可变参数总结 - stdarg.h

stdarg.h头文件中定义了一系列宏以及数据对象,用于支持可变参数的函数。 主要有: va_list //定义的数据对象 用于存放可变参数列表(省略号部分)代表的参量 va_start(ap,v) //用于将可变参数列表中第一个参量的地址复制给va_list定义的数据对象 va_arg(ap,t) //用于访问可变参数列表中参量内容,第一次调用访问第一个可变参量,第二次调用访问第二个可变参量.. 以此类推 va_end()

Kellery 687
上一篇: C语言中return,exit return exit的区别
下一篇: C语言中long long的用法
junecau
博客等级 码龄19年 125粉丝 3原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值