在stdarg.h文件中有如下几个宏定义:

[cpp]view plaincopy
  1. #include <vadefs.h>

  2. #define va_start _crt_va_start

  3. #define va_arg _crt_va_arg

  4. #define va_end _crt_va_end

  5. #endif  /* _INC_STDARG */

其定义在vadefs.h中分别为:

[cpp]view plaincopy
  1. #define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )

  2. #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) //第一个可选参数地址

  3. #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //下一个参数地址

  4. #define va_end(ap) ( ap = (va_list)0 ) // 将指针置为无效

在进程中,堆栈地址是从高到低分配的.当执行一个函数的时候,将参数列表入栈,压入堆栈的高地址部分,然后入栈函数的返回地址,接着入栈函数的执行代码,这个入栈过程,堆栈地址不断递减,一些***就是在堆栈中修改函数返回地址,执行自己的代码来达到执行自己插入的代码段的目的.

总之,函数在堆栈中的分布情况是:地址从高到低,依次是:函数参数列表,函数返回地址,函数执行代码段.

堆栈中,各个函数的分布情况是倒序的.即最后一个参数在列表中地址最高部分,第一个参数在列表地址的最低部分.参数在堆栈中的分布情况如下:

最后一个参数

  倒数第二个参数

  ...

  第一个参数

  函数返回地址

  函数代码段

代码示例:这里是一个可变参数的加法函数

[cpp]view plaincopy
  1. #include<stdio.h>

  2. #include<stdlib.h>

  3. #include<stdarg.h>

  4. /*功能:可变参数求和

  5. *参数:numCount参数个数 ...可变求和参数

  6. *返回值:参数相加的和

  7. */

  8. int sum(int numCount,...)

  9. {

  10. int result = 0;     //计算结果

  11. va_list ap;         //初始化指向可变参数列表的指针(typedef char* va_list)

  12. va_start(ap,numCount);          //将第一个可变参数的地址付给ap,即ap指向可变参数列表的开始

  13. for(int i = 0;i<numCount;i++)

  14. result += va_arg(ap,int);   //得到第一个可变参数的值,并且ap指针上移一个_INTSIZEOF(int),即指向下一个可变参数的地址.

  15. va_end(ap);                     //置空ap,即ap=(void *)0;

  16. return result;

  17. }

  18. int main(void)

  19. {

  20. printf("20+15+3+8=%d\n",sum(4,20,15,3,8));

  21. system("pause");

  22. return 0;

  23. }

转载于:https://blog.51cto.com/7212823/1202392

C可变参数详解及其函数设计相关推荐

  1. C语言传递可变参数详解

    C语言传递可变参数详解 1.可变参数详解 在有些情况下,我们需要传递的参数的个数是可变的.C 语言为这种情况提供了一个解决方案,它允许定义一个函数,能根据具体的需求接受可变数量的参数.可以使编程更加的 ...

  2. java 可变参数 详解(通俗易懂)

    目录 一.概述: 二.格式: 三.注意事项(使用规范): 四.代码演示: 演示规范①~③: 演示规范④: 演示规范⑤: 课堂练习: 代码演示: 输出结果: 五.英文版本讲解: 一.概述: java中, ...

  3. python可变参数教学,Python函数可变参数详解

    在实际使用函数时,可能会遇到"不知道函数需要接受多少个实参"的情况,不过好在 Python 允许函数从调用语句中收集任意数量的实参. 例如,设计一个制作披萨的函数,我们知道,披萨中 ...

  4. C#FindWindowEx参数详解

    FindWindowEx参数详解 本函数的其他内容在网络上都比较多,这里主要说一下它的参数设置和搜索结果的区别. 函数功能:在窗口列表中寻找与指定条件相符的第一个子窗口.该函数获得一个窗口的句柄,该窗 ...

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

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

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

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

  7. 定义一个没有参数的函数、输出python3次_Python函数参数详解,三天让你掌握python,不再是小白

    原标题:Python函数参数详解,三天让你掌握python,不再是小白 引言 随着程序功能的增多,代码量随之增大,此时仍不加区分地把所有功能的实现代码放到一起,将会使得程序的组织结构不清晰,可读性变差 ...

  8. python函数参数定义_Python函数定义及参数详解

    函数定义 首先我们来创建一个函数,输出指定范围内的斐波拉契数列(Fibonacci series). #!/usr/bin/env python #coding=utf-8 ''' Created o ...

  9. ioctl函数详解(参数详解,驱动unlocked_ioctl使用、命令码如何封装)

    @ioctl函数详解 一.ioctl函数的原型 在用户空间的函数原型 #include <sys/ioctl.h> int ioctl(int d, int request, ...); ...

最新文章

  1. 汽车行业要变天?数据告诉你,为什么说合资车企正在走向末路
  2. [译]发布ABP v0.19包含Angular UI选项
  3. redis、mysql、和php原生array数组效率对比
  4. 20190718每日一句
  5. 【车间调度】基于matlab遗传算法求解混合流水车间调度最优问题【含Matlab源码 901期】
  6. 程序设计语言及其文法
  7. abb的knx的数据库下载方法_ABB智能家居KNX方案.doc
  8. java 数字转换字母大写_大写字母或小写字母转换为数字
  9. 最好的降噪蓝牙耳机有哪些?目前最好的降噪蓝牙耳机推荐
  10. 吴恩达深度学习课程-Course 4 卷积神经网络 第一周 卷积神经网络编程作业(第一部分)
  11. jar包反编译工具(java-decompiler)
  12. 新⼀代USDP开源套件,可替代CDH的免费大数据套件平台及架构选型
  13. 开发利器IntelliJ IDEA—带你体验各种神奇操作
  14. C++学习日记#1.1——四元一次方程组进行Sor松弛迭代法求解(现已推向n元一次方程组进行Sor松弛迭代法求解)
  15. 浏览器修改主页不失效,打开浏览器弹出首页修改方法
  16. 白嫖freenom免费顶级域名
  17. C语言优惠套餐推荐系统
  18. DotNetCore CAP(分布式事务最终一致性)框架
  19. 【注意】加密与解密工具新年大礼包2007光盘提供下载
  20. 高通骁龙820A的硬件模块部分简介

热门文章

  1. nginx php unix负载,使用nginx配置多个php fastcgi负载均衡
  2. safari浏览器横屏怎么设置_Safari浏览器的几个小技巧你掌握了吗?
  3. 设计一个名为complex的类来表示复数_天线波束设计
  4. linux标准分发版的描述信息,如何查看Linux中系统版本信息
  5. 温度自动调节 c语言编写,室内温度自动调节控制系统课程设计(26页)-原创力文档...
  6. IIS服务器下做301永久重定向设置方法[图解]
  7. Locust接口性能测试
  8. 关于oracle中table函数的使用
  9. java 实现生产者-消费者模式
  10. 【commons】Bean工具类——commons-beanutils之BeanUtils