C语言的可变参数函数


目录
  • C语言 可变参数
    • 参数
    • 小例子
    • 实现相关的宏
    • 完整例子
    • 实现原理

C语言 可变参数

C 语言允许定义参数数量可变的函数,这称为可变参数函数。这种函数需要

  1. 固定数量的强制参数(mandatory argument)
  2. 数量可变的可选参数(optional argument)。

C 语言中最常用的可变参数函数例子是 printf()scanf()。这两个函数都有一个强制参数,即格式化字符串。格式化字符串中的转换修饰符决定了可选参数的数量和类型。

可变参数的个数(百分号的个数)、可变参数的类型(%s、%d等)

参数

可变参数函数的参数定义:

每一个强制参数来说,函数头部都会显示一个适当的参数,像普通函数声明一样。

参数列表的格式是强制性参数在前,后面跟着用三个小数点 "..." 表示这个位置可以有多个参数,参数的类型和个数不是固定的。

小例子

简明扼要的小例子:

int func(int, ... )  //int类型参数代表了可变参数个数
{
	//实现
}
 
int main()
{
   func(2, 2, 3);
   func(3, 2, 3, 4);
}

实现相关的宏

可变参数函数的实现:

  • 头文件

  • va_list 变量类型用来保存可变参数 "..." 位置等信息的参数列表。这种类型的对象也称为参数指针(argument pointer),它包含了栈中至少一个参数的位置。可以使用这个参数指针从一个可选参数移动到下一个可选参数。可以用 4 个宏来处理该参数指针

  • va_start 是初始化 va_list 参数表

    void va_start(va_list argptr,lastparam);
    //用第一个可选参数的位置来初始化 argptr 参数指针
    //该宏的第二个参数必须是该函数最后一个有名称参数的名称
    //必须先调用该宏,即初始化操作
    
  • va_arg 是从 va_list 参数表里面获取一个参数,并且指向下一个参数

    type va_arg(va_list argptr,type);
    //宏的第二个参数是刚刚被读入的参数的类型
    
  • va_end 释放 va_start 初始化参数表占用的资源,当不需要使用该参数指针时必须调用该宏。

    void va_end(va_list argptr);
    
  • va_copy 使用当前的 src 值来初始化参数指针 dest

    void va_copy(va_list dest, va_list src);
    

完整例子

一个完整使用的例子:

double add(int n,...)
{
    int i=0;
    double sum=0;
    va_list argptr;
    va_start(argptr,n); 		//初始化,n为可变参数个数
    for(int i=0;i

实现原理

可变参数的传递从右往左压入栈中,栈是向低地址拓展的,取参数时再从低到高(从左往右)。

64 位机器用 8 字节对齐, 32 位 4 位对齐

具体这一块相关的信息可以看操作系统或者编译原理中涉及用户栈和参数调用的过程。