可变参数列表解析

xiaoxiao2021-02-28  103

在函数的原型中,列出了函数期望接受的参数,但原型只能显示固定数目的参数。让一个函数在不同的时候接受不同数目的参数是不是可以呢? 首先我们来看看main函数的原型:

int main( int argc, char *argv[ ] , char *envp[ ] ) { program-statements }

第一个参数: argc是个整型变量, 表示命令行参数的个数(含第一个参数) 。 第二个参数: argv是个字符指针的数组, 每个元素是一个字符指针, 指向一个字 符串。 这些字符串就是命令行中的每一个参数(字符串) 。 第三个参数: envp是字符指针的数组, 数组的每一个原元素是一个指向一个环境 变量(字符串) 的字符指针。

下面我们来看一个例子: 使用可变参数,实现函数求未知参数部分n个数的平均值。

#include<stdio.h> #include<stdlib.h> #include<string.h> #include<stdarg.h>//可变参数列表是通过宏实现的,这些宏定义于stdarg.h头文件中 int average(int n,...)//省略号提示此处可能传递数量和类型未确定的参数 { va_list arg; //相当于char*arg int i=0; int sum=0; va_start(arg,n); for(i=0;i<n;i++) { sum+=va_arg(arg,int); } va_end(arg); return sum/n; } int main() { int ret=average(5, 1,2,3,4,5); printf("ret=%d\n",ret); return 0;

注: stdarg.h宏是标准库的一部分,这个头文件声明了一个类型va_list和三个宏——va_start,va_arg和va_end。我们可以声明一个类型为va_list的变量,与这几个宏配合使用,访问参数的值。 对上面代码分析:

可变参数的实现过程是使用宏的封装。 只要完成替换, 我们就可以自行分析了。 va_start(arg,n); 转到定义#define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) ) 替换后:#define va_start(arg,n) (arg=(va_list)&n+ _INTSIZEOF(n) //向上取整 sum+=va_arg(arg,int); 转到定义#define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) 替换后:sum+=(*(int*)((arg+=4)-4));

同理使用可变参数,实现函数求未知参数部分n个数中的最大值。

#include<stdio.h> #include<stdlib.h> #include<string.h> #include<stdarg.h> int Max(int n,...) { int i=0; int max=0; int tmp=0; va_list arg; va_start(arg,n); for(i=0;i<n;i++) { if(max<(tmp=va_arg(arg,int))) { max=tmp; } } return tmp; } int main() { int max=Max(5, 1,2,3,4,5); printf("%d\n",max); return 0; }

可变参数的限制 1,可变参数必须从头到尾逐个访问。 如果你在访问了几个可变参数之后想半途,终止, 这是可以的, 但是, 如果你想一开始就访问参数列表中间的参数, 那是不行的。 2,参数列表中至少有一个命名参数。 如果连一个命名参数都没有, 就无法使用va_start。 3,这些宏是无法直接判断实际存在参数的数量。 4,这些宏无法判断每个参数的是类型。 5,如果在va_arg中指定了错误的类型, 那么其后果是不可预测的。

转载请注明原文地址: https://www.6miu.com/read-70814.html

最新回复(0)