一直以来对ioctl这类参数可变的函数感到好奇,但不明白它的具体实现,查阅了一下《c和指针》,在这总结一下。
可变参数列表时通过定义于中的宏来实现的,它是标准库的一部分。该文件主要声明了一个类型va_list和三个宏(va_start、va_arg、va_end)。使用的时候先声明一个va_list类型的变量,再配合几个宏使用,访问参数的值。
《c和指针》中有两个例子对比说明了可变参数列表相对固定参数列表的优点;程序功能对输入的参数取绝对值;假设最多输入5个参数(固定列表需要)。
固定列表:
- float
- arverage( int n_values, int v1, int v2, int v3, int v4, int v5)
- {
- float sum = v1;
- if (n_values >= 2 )
- sum +=v2;
- if (n_values >= 3 )
- sum +=v3;
- if (n_values >= 4 )
- sum +=v4;
- if (n_values >= 5 )
- sum +=v5;
- return sum / n_values;
- }
可变参数列表:
- #include <stdarg.h>
- float
- arverage( int n_values,...)
- {
- va_list var_arg;
- int count;
- va_start(var_arg,n_values);
- for (count = 0; count < n_values; count +=1){
- sum += va_arg(var_arg,int);
- }
- va_end(var_arg);
- return sum / n_values;
- }
用蓝色标注的语句就是我们在使用可变参数列表中需要用到的类型和宏;
第三句:参数列表中的省略号提示此处可能传递数量和类型都是未确定的。
第五句:声明va_list类型的变量var_arg,用于访问参数列表的未确定部分。
第七句:va_start初始化变量var_arg。第一个参数表示变量的名字,第二个参数是省略号前最后一个有名字的参数。初始化过程把var_arg变量设置为指向可变参数部分的第一个参数。
第九句:va_arg用来访问参数,它有两个参数:va_list的变量var_arg、参数列表中下一个参数的类型。va_arg返回这个参数的值,并使var_arg指向下一个可变参数。
第十一句:访问完毕最后一个可变参数之后,调用va_end。
对于一个值的类型不能简单的通过检查它的位模式来判断,所有这些宏不能实现下面两个功能:
1、无法判断实际存在的参数的数量。
2、无法判断每个参数的类型。
下面再举个例子,强调一下va_start的第二个参数是省略号前最后一个有名字的参数。程序功能:打印不同级别的提示信息。
- void
- debug_print_msg( int dbgLevel, char* aFormat, ... )
- {
- va_list list;
- va_start( list, aFormat );
- if (dbgLevel >= g_curDbgLevel)
- {
- switch(dbgLevel)
- {
- case DBG_ERR:
- fprintf(stderr, "ERROR: ");
- break;
- case DBG_WAR:
- fprintf(stderr, "WARNING: ");
- break;
- case DBG_MSG:
- fprintf(stderr, "MSG: ");
- break;
- }
- vfprintf(stderr, aFormat, list);
- fprintf(stderr, "\n");
- fflush(stderr);
- }
- va_end( list );
- }
阅读(2541) | 评论(0) | 转发(0) |