C 语言函数形参当中的 “...“ 是什么意思, va_start()、va_arg()、va_copy() 和 va_end()

举个 “…” 的简单例子

在 C 语言中,形参中的 “…” 代表一个可变参数列表。这个特性允许函数接受不定数量的参数,这在需要处理数量未知的参数的情况下非常有用。

具体来说,在函数定义中使用 "..." 来声明可变参数列表,形如:

int func_name(int arg1, ...);

其中 "..." 表示函数参数的可变部分,可以接受任意数量的参数,类型和数量在调用时决定。可变参数的获取和处理通常需要使用 C 语言的 <stdarg.h> 头文件中定义的函数,如 va_start、va_arg、va_copy 和 va_end

举个例子,以下是一个计算可变参数平均值的函数:

#include <stdarg.h>

double average(int num, ...) {
   va_list valist;
   double sum = 0.0;
   int i;

   /* 初始化 valist */
   va_start(valist, num);

   /* 计算所有可变参数的和 */
   for (i = 0; i < num; i++) {
      sum += va_arg(valist, int);
   }

   /* 结束可变参数的获取 */
   va_end(valist);

   /* 计算平均值 */
   return sum/num;
}

在这个例子中,函数 average 的第一个参数是需要处理的整数数量,接下来的 “…” 表示可变参数列表。
函数内部通过 va_list 定义一个指向可变参数的指针 valist,并使用 va_start 初始化 valist,va_arg 获取参数值,va_end 结束可变参数的获取,最后计算平均值并返回。这样,调用该函数时就可以传递任意数量的整数参数了。


va_list 的分析

va_list 是C语言中提供的一种处理可变参数列表的数据类型,其实质是一个指针,指向可变参数列表中下一个参数的位置。va_list类型通常是由 va_start()、va_arg()、va_copy() 和 va_end()等函数调用来初始化和更新。

具体地说:
1、va_start()函数将 va_list指针初始化为可变参数列表中的第一个参数
2、然后使用 va_arg()函数依次读取参数列表中的各个参数。
3、va_end()函数用于结束可变参数的处理,并且会将 va_list 指针清空。
4、va_copy()函数用于复制一个可变参数列表,通常用于将可变参数列表作为参数传递给另一个函数。

va_list 的结构类型可以因不同的编译器和系统而有所不同,但通常定义为指向堆栈中可变参数列表的指针类型。在32位的Linux系统中,va_list的定义通常如下所示:

typedef char* va_list;

在64位的Linux系统中,va_list的定义通常如下所示:

typedef struct {
    void * gp_offset;
    void * fp_offset;
    void * overflow_arg_area;
    void * reg_save_area;
} va_list[1];

因此,可以看出,va_list的结构类型实际上并不是重点,重要的是使用它的方式和配套的可变参数处理函数。


va_start 的分析

va_start 是一个宏定义,它的作用是初始化可变参数列表。
在调用可变参数函数时,编译器需要知道参数列表的起始位置和类型,而 va_start 正是为了获取这些信息。

va_start 的原型定义在 <stdarg.h> 头文件中,一般的定义如下:

void va_start(va_list ap, last_arg);

va_list 是一个指向参数列表的指针
last_arg 是参数列表中最后一个固定参数,即可变参数列表的前一个参数。
宏定义 va_start 可以用来初始化 va_list 指针。

va_start 宏定义的语法格式如下:

va_start(ap, last_arg)

其中,ap 是一个指向参数列表的指针,last_arg 是参数列表中最后一个固定参数,即可变参数列表的前一个参数。

在使用 va_start 宏定义初始化 va_list 指针后,我们就可以通过 va_arg 宏定义来访问可变参数列表中的每个参数了。使用完可变参数列表后,应该调用 va_end 宏定义来清理资源。

注意:va_start 只是初始化了指向参数列表的指针,并不会复制可变参数列表,因此在使用可变参数列表时应该非常小心,以避免访问未定义的内存地址,导致程序崩溃或出现其他问题。


  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

想文艺一点的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值