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

Posted 想文艺一点的程序员

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 只是初始化了指向参数列表的指针,并不会复制可变参数列表,因此在使用可变参数列表时应该非常小心,以避免访问未定义的内存地址,导致程序崩溃或出现其他问题。


以上是关于C 语言函数形参当中的 “...“ 是什么意思, va_start()va_arg()va_copy() 和 va_end()的主要内容,如果未能解决你的问题,请参考以下文章

c语言中形参和实参的区别?

c语言中swap 是啥意思?

C语言中可否定义一个函数,这个函数的形参数量可以改变?

c语言 指针传参

C语言中stdout是啥意思?

C语言的两个问题: 所有的递归程序均可以用非递归算法实现?递归函数中的形式参数是自动变量吗? c语言中