加载中…
个人资料
阿涵-_-
阿涵-_-
  • 博客等级:
  • 博客积分:0
  • 博客访问:1,495,192
  • 关注人气:161
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
相关博文
推荐博文
谁看过这篇博文
加载中…
正文 字体大小:

C语言实现可变参数函数

(2010-12-18 08:39:56)
标签:

c语言

实现

可变参数

函数

va_list

va_start

va_arg

va_end

it

分类: 编程语言

 

C语言中可变参数列表是通过宏来实现的,这些宏定义于stdarg.h头文件,它是标准库的一部分。

C语言的可变参数函数主要要用到了一个类型va_list和三个宏——va_startva_argva_end

C语言的可变参数函数必须以某种方式提供参数的个数。

 

我们可以声明一个类型为va_list的变量,与这几个宏配合使用,访问参数的值。这个变量通过调用va_start来初始化。它的第1个参数是va_list变量的名字,第2个参数是省略号前最后一个有名字的参数。初始化过程把var_arg变量设置为指向可变参数部分的第一个参数。

为了访问参数,需要使用va_arg,这个宏接受两个参数:va_list变量和参数列表中下一个参数的类型。va_arg返回这个参数的值,并使var_arg指向下一个可变参数。

需要注意的是,可变参数必须从头到尾按照顺序访问,不可以一开始就访问参数列表中间的参数。

当访问完毕最后一个可变参数之后,需要调用va_end

 

 

给一段示例代码:

 

//可变参数的例子

 

#include <stdarg.h>

//函数至少需要一个确定的参数

 

float average(int n_values,...){

    va_list var_arg;

    int count;

    float sum=0;

    

    //初始化,准备访问可变参数,它的第1个参数是va_list变量的名字,第2个参数是省略号前最后一个有名字的参数。

    va_start(var_arg,n_values);

    

    //取各个参数

    for(count=0;count<n_values;count++){

        sum+=va_arg(var_arg,int);        

    

    

    //完成

    va_end(var_arg);

    return sum/n_values; 

 

int main(){

    printf("%f\n",average(5,2,2,3,3,5));

    system("pause");

    return 0;

}


——以上例子选自《C和指针》,Kenneth A.Reek著,徐波译,有兴趣的朋友可以看原著,是本经典著作。


 

 

笔者查看了一个stdarg.h这个头文件:内容只有一点点:

//

// This is just an RC_INVOKED guard for the real stdarg.h

// fixincluded in gcc system dir. One day we will delete this file.

//

#ifndef RC_INVOKED

#include_next<stdarg.h>

#endif

 

这个头文件中用到了#include_next,于是顺便查了一下#include_next的用法。 #include_next被用于头文件中(#include既可用于头文件中又可用于.c文件中)来包含其他的头文件,而且包含头文件的路径比较特殊:从当前头文件所在目录之后的目录来搜索头文件。举个例子,头文件的搜索路径一次为A,B,C,D,E. #include_next所在的当前头文件位于B目录那么#include_next使得预处理器从C,D,E目录来搜索#include_next所指定的头文件。这样的用意似乎是让变参的实现方法可以由不同的编译器来决定,简单地说,就是不同的编译器可以有不同的头文件。

 

于是笔者重新搜索了一下stdarg.h这个头文件,果然在别的文件夹下发现了新的文件(同名文件),看一下va_list这个变量,有

typedef __gnuc_va_list va_list;

typedef __builtin_va_list __gnuc_va_list;

查找了一下__builtin_va_list这个变量,发现是这个gcc 编译器内置的。下面是来自http://www.ajaxstu.com/Cbiancheng/99427.html 的一些解释。

You will always have this problem operating on preprocessed source.
Other compilers have similar built-in definitions, such as
__NAN__.  Preprocessed source is compiler-specific.
__builtin_va_list is builtin type, not macro.  Much like how "int" is not macro... GCC will provide it.

That type is exactly what it's name implies -- it is built in to the compiler.  It is not macro, but rather predefined in the same manner as "int".

可见__builtin_va_list这个变量跟int变量一样,是由编译器来实现的。

我的更多文章:

0

阅读 评论 收藏 转载 喜欢 打印举报/Report
  • 评论加载中,请稍候...
发评论

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

      

    新浪BLOG意见反馈留言板 电话:4000520066 提示音后按1键(按当地市话标准计费) 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有