C 可变参数
C - 可变参数 (可变参数函数)
Section titled “C - 可变参数 (可变参数函数)”有时,创建可以接受可变数量参数而不是固定数量参数的函数会很有用。标准库中的例子包括 printf 和 scanf。这些函数称为 可变参数函数 (variadic functions)。
C 语言在 <stdarg.h> 头文件中提供了实现此类函数的机制。
声明可变参数函数
Section titled “声明可变参数函数”可变参数函数的声明必须至少有一个具名参数 (named parameter),后跟省略号 (...) 作为最后一个参数。
return_type function_name(type fixed_param1, ...);固定参数正常访问。省略号代表参数列表的可变部分。
访问可变参数
Section titled “访问可变参数”<stdarg.h> 头文件提供了宏来处理可变参数:
va_list: 一个类型,用于存储关于可变参数列表的信息。va_start(va_list ap, last_fixed_param): 初始化va_list变量 (ap)。last_fixed_param必须是省略号前的最后一个具名参数的名称。必须在访问任何可变参数之前调用。va_arg(va_list ap, type): 从列表 (ap) 中检索下一个参数,并假设它具有指定的type。它还会在ap内部将内部指针指向下一个参数。关键是,函数必须知道如何确定下一个参数的类型(例如,通过像printf那样的格式字符串,或通过固定参数传递的数量)。va_end(va_list ap): 清理va_list。必须在函数返回之前,处理完所有参数后调用。va_copy(va_list dest, va_list src): (C99) 创建va_list状态的副本。如果需要多次遍历参数,这很有用。
示例:平均值函数
Section titled “示例:平均值函数”让我们创建一个函数,计算可变数量的整型参数的平均值。我们将可变参数的数量作为第一个固定参数传递。
#include <stdio.h>#include <stdarg.h> // 可变参数函数所需
// 计算后面 'count' 个整型参数的平均值double average(int count, ...) { // 'count' 是最后一个固定参数 if (count <= 0) { fprintf(stderr, "Error: Average requires at least one number.\n"); return 0.0; // 或以其他方式处理错误 }
va_list args; // 1. 声明一个 va_list 变量 double sum = 0.0;
// 2. 初始化 'args' 指向第一个可变参数 va_start(args, count);
// 3. 循环遍历并访问每个可变参数 for (int i = 0; i < count; i++) { // 检索下一个参数,假设它是 int 类型 int current_arg = va_arg(args, int); sum += current_arg; }
// 4. 清理 va_list va_end(args);
return sum / count;}
int main(void) { // 使用不同数量的参数调用 average printf("Average of 2, 3, 4, 5 = %.2f\n", average(4, 2, 3, 4, 5)); printf("Average of 5, 10, 15 = %.2f\n", average(3, 5, 10, 15)); printf("Average of 100 = %.2f\n", average(1, 100)); printf("Average of nothing = %.2f\n", average(0)); // 处理错误情况
return 0;}输出:
Average of 2, 3, 4, 5 = 3.50Average of 5, 10, 15 = 10.00Average of 100 = 100.00Error: Average requires at least one number.Average of nothing = 0.00重要注意事项
Section titled “重要注意事项”- 类型安全 (Type Safety): 可变参数函数会绕过对可变参数的常规类型检查。函数必须有一种可靠的方式来确定使用
va_arg检索的每个参数的类型。传递错误类型的参数会导致未定义行为。 - 参数提升 (Argument Promotion): 默认参数提升适用于可变参数(例如,
float会提升为double,char/short会提升为int)。你必须在va_arg中使用提升后的类型(例如,使用va_arg(ap, double)来检索作为float传递的参数)。 - 机制 (Mechanism): 函数需要一种机制来知道传递了多少参数以及它们的类型(例如,一个计数参数、一个格式字符串、一个哨兵值如
NULL)。
可变参数函数提供了灵活性,但需要仔细实现以确保正确性并避免运行时错误。