可变参数浅析
来源:互联网 发布:华为机顶盒软件下载 编辑:程序博客网 时间:2024/06/05 22:31
在函数的原型中,列出了函数期望接受的参数,但原型只能显示固定数目的参数,那么,让一个函数在不同需求下接受不同的参数是不是可以呢?答案是肯定的,比如我们的printf函数就是一个参数可变的函数。下面以一个求取平均值程序为例,帮助我们理解可变参数列表
#define _CRT_SECURE_NO_DEPRECATE#include <stdio.h>#include <stdarg.h>#include <Windows.h>int average(int num, ...)//num代表第一个参数,...代表可变参数//{ /*char*p = #定义一个指针,并指向第一个形参地址,即指针初始化 int i = 0; int sum = 0; while (i <= num) { sum += *(int *)(p + 4 * i);从第一个形参地址处开始取值,直到取出所有数并求和 i++; }// va_list arg;//功能类似定义一个char*p int sum = 0; int n = 0; va_start(arg, num);/* 初始化,找到第一个形参地址*/ while (n--) { sum += va_arg(arg, int); /*功能类似sum += *(int *)(p + 4 * i);*/ } va_end(arg);/*arg=NULL*/ return sum / num;/*求平均值*/}int main(int argc,char*argv[],char *env[]){ int a = 2; int b = 4; int c = 6; int avg1 = average(a, b, c); int avg2 = average( a, b); printf("avg1=%d\n", avg1); printf("avg2=%d\n", avg2); system("pause"); return 0;}
可变参数列表是通过宏来实现的。这些宏类似于stdarg.h头文件,他是标准库的一部分。这个头文件声明了一个类型va_list和三个宏———va_start,va_end,va_arg,有了这个宏以后,我们可以声明一个类型为va_list的变量(va_list arg类似一个定义一个 char *p),与这几个宏配合使用来访问参数的值
函数声明了一个va_arg用来访问参数列表中未确定的部分,这个变量通过调用va_start来初始化,他的第一个参数是va_list变量的名字,初始化过程把va_arg变量设置为指向可变参数部分的第一个参数,
为了访问参数,我们需要,需要使用va_arg,这个宏接受两个参数,va_list变量和可变参数列表中下一个参数的类型(在本案中,参数都是整形。而在有些函数中,你需要通过前面的数据来判断下一个参数了的类型)va_arg返回这个参数的值,并是va_arg指向下一个可变参数,最后,当访问完最后一个可变参数后,需要调用va_end,使访问过程结束。
可变参数函数调用要满足三个基本条件
- 参数列表中至少有一个命名参数,如果第一个连一个命名参数都没有,你就无法使用va_start。只有知道第一个命名参数,才能找到函数形参创建的起始位置,便于后面参数的查找与提取。
- 参数的类型,只有知道参数的类型才能正确的找到第一个形参后面的形参,这些宏无法判断参数的类型
- 参数的个数,决定指针查找参数这个过程在哪停止,函数实参个数有限,所以查过程也是有终点的,这些宏无法判断参数的数量。
当这三个基本条件满足后,函数调用就可以进行了。这里需要注意的是可变参数形参是从右往左依次创建的,具体过程参照我的博客《深度理解函数》中有详细介绍。创建的结果就是最左边的参数地址最低。如下图a的地址最低,其次是b,c的地址最高,可以参照下图帮助理解
当指针找到第一个形参地址时并取数,(数据是连续存储的)往后查找取数时需要依次查找,由于参数类型是int型,所以指针依次要越过四字节才能找到下一个地址取数,直到找到最后一个参数地址取数,(参数运算略)对可变参数全部操作即结束
- 浅析可变参数列表
- 浅析可变参数
- 浅析可变参数列表
- 浅析可变参数
- 可变参数列表浅析
- 可变参数浅析
- 浅析可变参数列表
- 参数个数可变函数浅析
- 浅析可变参数列表的使用
- 浅析可变参数列表及实例分析
- C语言中可变参数函数实现原理浅析
- C语言中可变参数函数实现原理浅析
- 可变参数
- 可变参数
- 可变参数
- 可变参数
- 可变参数
- 可变参数
- jquery之animate()和css3 animation属性的本质区别
- HashMap,LinkedHashMap,TreeMap的有序性
- java--面向对象之多态2
- SSL P2278 Oliver的救援
- springcloud实战之5 服务消费者(ribbon)
- 可变参数浅析
- DecimalFormat类使用
- Bootstrap简介
- 微信小程序—picker(滚动选择器)
- Redis 一、数据结构与对象--五大数据类型的底层结构实现
- [CQOI2016]不同的最小割
- java web实验作业9
- HTML 路由 换div
- 动态可订制属性的 PropertyGrid