Loading

1 什么是可变参数

可变参数是 C 语言和 C++ 语言中的一个特性,它允许函数定义可变数量和可变类型的参数。例如,printfscanf等函数的实现就使用了可变参数,以下是printfscanf的函数声明:

int printf(const char *, ...);
int scanf(const char *, ...);

在形参列表里,省略号...即为可变参数列表,用于表示可变参数。

2 如何处理可变参数

在C/C++语言中,提供了头文件<stdarg.h>用于处理可变参数。通过引用该头文件,我们可以使用在该头文件中提供的一些可变参数处理宏和处理函数。

2.1 可变参数宏

C99标准新增的__VA_ARGS__预定义标识符即为可变参数宏,其用于在宏定义中代表可变参数列表。通过它,我们可以在宏定义时传入可变参数,并在宏展开时将这些参数插入到指定的位置。如下所示,我们定义了一个打印调试信息的宏,且在每次输出时都自动添加换行符,使用__VA_ARGS__来接收和展开可变参数:

#include <stdio.h>

#ifdef DEBUG
#define DEBUG_PRINT(fmt, ...) \
    do { \
        printf(fmt "\n", ##__VA_ARGS__); \
    } while (0)
#else
#define DEBUG_PRINT(fmt, ...)
#endif

在上面这个例子中,我们需要额外注意##运算符。##运算符的具体用法在《[C/C++]# 和 ## 运算符详解》这篇文章中有介绍,其是记号粘贴运算符,用于将两个记号粘连为一个记号,但是在此处,其还有一个额外的用法,即用于去掉当可变参数宏__VA_ARGS__为空时,多余产生的逗号。

2.2 可变参数解析宏

对于可变参数函数,C/C++语言提供了以下可变参数解析宏用于处理函数参数:

  • va_list:一种用于存储可变参数信息的类型,用于声明一个用于访问函数可变参数的变量
  • va_start(ap, param):用于初始化va_list类型的变量,使其指向函数参数列表中的第一个可变参数
  • va_arg(ap, type):用于访问va_list中的下一个可变参数,并将其转换为指定的类型
  • va_end(ap):用于清理va_list变量,在调用va_start之后必须调用va_end

通过灵活使用这些宏,可以省去解析可变参数的麻烦,以下是一个简单的使用示例:

#include <stdio.h>
#include <stdarg.h>

void print_numbers(int count, ...) {
    va_list args;
    va_start(args, count);  // 初始化 va_list 变量

    for (int i = 0; i < count; i++) {
        int num = va_arg(args, int);  // 获取下一个 int 类型的参数
        printf("%d\n", num);
    }

    va_end(args);  // 清理 va_list 变量
}

int main() {
    print_numbers(3, 10, 20, 30);  // 打印 10, 20, 30
    return 0;
}

2.3 可变参数函数

C/C++语言提供了一些可以直接处理可变参数的函数,例如vprintfvsprintfvsnprintfvfprintfvsfscanf等,下面讲解vprintf函数的使用示例,其余函数的用法也基本大差不差。

vprintf函数的函数原型如下所示:

#include <stdio.h>

int vprintf(const char *format, va_list args);
  • 形参:
    1. format:这是一个格式化字符串,指定了输出的格式
    2. args:这是一个va_list类型的参数,表示一个变参列表
  • 返回值:返回输出的字符数(不包括终止的空字符),如果发生错误,则返回一个负数

vprintf函数的使用示例如下所示,演示了如何实现一个自定义的打印函数:

#include <stdio.h>
#include <stdarg.h>

// 自定义函数,接受一个格式化字符串和一个可变参数列表
void my_print(const char *format, ...) {
    va_list args;
    va_start(args, format);  // 初始化 va_list 类型的变量 args
    vprintf(format, args);   // 使用 vprintf 输出格式化字符串
    va_end(args);            // 清理 va_list 类型的变量
}

int main() {
    my_print("Hello, %s! You have %d new messages.\n", "Alice", 5);
    return 0;
}

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

👤本站访客数: 👁️本站访问量: