Bootstrap

【C 高阶】可变参数

1. 简介

可否想过 C 语言中最常见常用的 printf() 函数是如何做到接收任意类型、任意数量的参数的呢?

实际上,printf() 中通过可变参数特性来接收任意类型、任意数量的参数。可变参数通过占位 ... 显式指示,例如以下函数的形参就是可变参数:

void fun (...)
{
   
    // do something
}

2. 相关 API

在函数中怎么使用这些可变参数呢?C 语言在头文件 <stdarg.h> 中提供了三个操作可变参数的 API:va_startva_argva_end,前缀 va 即 variable argument(可变参数)。

这三个 API 都为函数宏,功能如下:

  • va_start

va_start 的声明如下(伪代码):

void va_start (va_list ap, last);

ap 为可变参数列表对象,需要在调用 va_start 前创建。va_list 内包含一个成员指针,即 ap 内有指向可变参数的指针。

last 为可变参数的占位符前的形参。一般情况下,使用可变参数的函数需要提供一个形参用于函数调用时指定可变参数的个数,否则在程序中将无法得知具体的可变参数个数。

va_start 用于初始化可变参数列表对象,把 ap 内的可变参数指针指向 last 的下一个参数即可变参数列表的第一个参数。

  • va_arg

va_arg 的声明如下(伪代码):

type va_arg (va_list ap, type);

type 为可变参数的数据类型。

va_arg 用于获取 ap 的可变参数参数指针所指的参数并作为返回值。获取后该指针将根据 type 偏移一定字节数,指向下一个可变参数。

需要注意的是,使用 GCC 编译时,当可变参数类型为 char 或 short 即少于四个字节,可变参数将占据四个字节大小。因此,此时的函数实参 type 应显式指示为 int。

  • va_end

va_end 的声明如下(伪代码):

void va_end (va_list ap)
;