函数原型: int printf(const char *format[,argument]...)
       返 回 值: 成功则返回实际输出的字符数,失败返回-1.
 函数说明:
       在printf()函数中,format后面的参数个数不确定,且类型也不确定,这些参数都存放在栈内.调用printf()函数时,根据format里的格式("%d %f...")依次将栈里参数取出.而取出动作要用到va_arg、va_end、va_start这三个宏定义,再加上va_list.
     (1)va_list事实上是一char *类型,即:
            typedef char* va_list;
     (2)三个宏定义:
            #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,type)  ( *(type *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) 
            #define va_end(ap)          ( ap = (va_list)0 ) 
   【attention】C语言中可变参数的原理---printf()函数 
            int printf(const char* format,...);   
      使用过C语言的人所再熟悉不过的printf函数原型,它的参数中就有固定参数format和可变参数(用”…”表示).而程序员又可以用各种方式来调用printf,如: 
            printf("%d ",value);   
            printf("%s ",str);

printf("the number is %d,string is:%s ",value,str); 
       可以看出,该函数的参数格式不固定,参数类型不固定.在C语言中使用宏来处理这些可变参数.这些宏看起来很复杂,其实原理挺简单,即根据参数入栈的特点从最靠近第一个可变参数的固定参数开始,依次获取每个可变参数的地址.
 (1)宏va_start
      通过该宏定义可以获取到可变参数表的首地址,并将该地址赋给指针ap.
 (2)宏va_arg
      通过该宏定义可以获取当前ap所指向的可变参数,并将指针ap指向下一个可变参数.注意,该宏的第二个参数为类型.
 (3)宏va_end
      通过该宏定义可以结束可变参数的获取.

程序员通过这三个宏定义就可以实现对可变参数的处理.例如:

#include <stdio.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,type)  ( *(type *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )   
   #define va_end(ap)       ( ap = (va_list)0 )   
  
int cal_val(int c, ...)   
{   
    int sum = c;   
    va_list ap;              //声明指向char型的指针  
    va_start(ap,c);          //获取可变参数列表的首地址,并赋给指针ap  
  
    c = va_arg(ap,int);      //从可变参数列表中获取到第一个参数(返回值即为参数)  
    while(0 != c)   
    {   
        sum += c;   
        c = va_arg(ap,int);  //循环的从可变参数列表中获取到参数(返回值即为参数)  
    }  
    va_end(ap);              //结束从可变参数列表中获取参数  
    return sum;   
}    
   
int main(int argc, char* argv[])   
{   
    int value1;  
      
    value1 = cal_val(1,2,3,4,5,6,7,8,9,0);   
    printf("value1=%d/n",value1);  
    value2 = cal_val(6,7,8,9,0);   
    printf("value2=%d/n",value2);  
      
    return 0;   
}

转载于:https://www.cnblogs.com/huty/p/8517288.html

【C/C++开发】C语言实现函数可变参数相关推荐

  1. C语言_函数可变参数列表

    函数可变参数列表的应用和原理 在网上看到各位前辈关于这部分的介绍有些是过于简洁,有些则是过于晦涩,有的代码拿出来甚至在编译器上跑不过去,所以在这里讲一下自己对于可变参数的认识,若有不正确的地方,欢迎各 ...

  2. C语言中函数可变参数解析

    大多数时候,函数中形式参数的数目通常是确定的,在调用时要依次给出与形式参数对应的所有实际参数.但在某些情况下希望函数的参数个数可以根据需要确定.典型的例子有 大家熟悉的函数printf().scanf ...

  3. c语言 函数多个参数,C语言函数可变参数

    C语言函数可变参数教程 可变参数的函数必须至少有一个强制参数,可选参数的类型可以变化.可选参数的数量由强制参数的值决定,或由用来定义可选参数列表的特殊值决定. 对于每一个强制参数来说,函数头部都会显示 ...

  4. 【C语言进阶深度学习记录】三十九 C语言中的可变参数(参数可变的函数)

    用过printf()函数的热都知道,printf的参数可以有多个,它是可变的,根据我们输出参数的类型以及个数的不同来确定参数.今天来学习C语言中参数可变的函数是如何实现的. 文章目录 1 可变参数 2 ...

  5. c语言中的函数可变参数列表相关的三个宏

    在stdarg.h头文件中声明了一个类型va_list和3个与函数可变参数列表有关的宏:va_start.va_arg.va_end. #include<stdarg.h> //包含宏相关 ...

  6. c语言理解参数,c语言中对可变参数列表的简单理解

    函数原型中一般情况下参数的数目是固定的,但是如果想在不同的时候接收不定数目的参数时该怎么办呢?c语言提供了可变参数列表来实现. 可变参数列表是通过宏来实现的,这些宏定义在stdarg.h的头文件中.头 ...

  7. python 函数参数列表_Python 函数可变参数列表*args和**kwargs

    许多语言都支持可变参数列表,python也不例外.python的可变参数列表有点不太一样,有两种类型的可变参数列表,一种是元组,一种是字典. 一,元组参数列表: (1)函数定义形式:def func( ...

  8. python中可变参数*args传入函数时的存储方式为_python 中文读法详解Python函数可变参数定义及其参数传递方式...

    Python函数可变参数定义及其参数传递方式详解 python中 函数不定参数的定义形式如下 1. func(*args) 传入的参数为以元组形式存在args中,如: def func(*args): ...

  9. python函数中可变参数的传递方式是_详解Python函数可变参数定义及其参数传递方式...

    Python函数可变参数定义及其参数传递方式详解 python中 函数不定参数的定义形式如下 1. func(*args) 传入的参数为以元组形式存在args中,如: def func(*args): ...

最新文章

  1. linux网卡设置adsl上网,Linux下设置ADSL自动拨号上网
  2. 网站被黑你隔了多久才知道?
  3. 计算机体系结构:嵌入式方法_计算机考研——计算机二级学科详解
  4. poj 1283(递推ordp)
  5. 音视频技术开发周刊 | 184
  6. Element-UI-快速入门(极简教程)
  7. URL Loading System 概览
  8. 数据挖掘原理与算法 kNN算法
  9. Java面向对象的继承
  10. 1.4_2 Axure RP 9 for mac 高保真原型图 - 案例1 【基础】模仿微信页面
  11. [Pytorch系列-26]:神经网络基础 - 多个带激活函数的神经元实现非线性回归
  12. 前端必备的开发工具推荐——VScode代码编辑器
  13. 【内网安全】——数据库提权姿势
  14. 分享99个PHP源码,总有一款适合您
  15. C#编写画直线,简单画线,鼠标交互画线,画一条线
  16. 截取计算机全屏画面的方法有,电脑怎么截图全屏 详细方法介绍
  17. php中.=是什么意思,javascript中$符号是什么意思?
  18. 【Java学习笔记】(二)Java平台和Java虚拟机
  19. 转】oracle 小数格式化为百分数
  20. NPOI 导入导出和Excel版本,错误文件扩展名和文件的格式不匹配

热门文章

  1. 在fedora下面安装ftp服务器
  2. php关于ob_start('ob_gzhandler')启用GZIP压缩的bug
  3. POJ 2386 Lake Counting DFS水水
  4. Effective Java第七条:避免使用终结方法
  5. matlab delete、clf、cla、close、closereq删除对象
  6. Thread的run()与start()的区别
  7. Kali linux安装漏洞扫描工具Nessus安装指南
  8. 单例模式(饿汉式和懒汉式)
  9. android 记录路线轨迹_基于百度地图SDK记录运动轨迹
  10. 复旦大学计算机保研经历,#易保研#经验分享 | 个人经历分享,圆梦复旦大学!...