在 C 語言中,可變參數列表(Variable Argument List)通過 stdarg.h 頭文件提供的宏和函數來實現。它允許函數接受可變數量的參數,類似於 printf 和 scanf 這樣的函數。本文介紹與可變參數列表相關的函數和用法。
核心宏和函數
stdarg.h 提供了以下宏和函數來處理可變參數列表:
| 宏/函數 | 作用 |
|---|---|
va_list |
定義一個變量,用於存儲可變參數列表。 |
va_start() |
初始化 va_list,使其指向可變參數列表的第一個參數。 |
va_arg() |
從 va_list 中獲取下一個參數,並指定其類型。 |
va_end() |
清理 va_list,結束可變參數列表的訪問。 |
va_copy() |
複製一個 va_list(C99 標準引入)。 |
使用步驟
使用可變參數列表的典型步驟如下:
- 定義一個
va_list類型的變量。 - 使用
va_start()初始化va_list。 - 使用
va_arg()逐個獲取參數。 - 使用
va_end()清理va_list。
示例代碼
以下是一個簡單的示例,演示如何使用可變參數列表實現一個求和函數:
#include <stdio.h>
#include <stdarg.h>
// 定義一個可變參數函數,計算任意數量整數的和
int sum(int count, ...) {
int total = 0;
va_list args; // 定義 va_list 變量
va_start(args, count); // 初始化 args,使其指向第一個可變參數
for (int i = 0; i < count; i++) {
int num = va_arg(args, int); // 獲取下一個 int 類型的參數
total += num;
}
va_end(args); // 清理 args
return total;
}
int main() {
printf("Sum: %d\n", sum(3, 10, 20, 30)); // 輸出 60
printf("Sum: %d\n", sum(5, 1, 2, 3, 4, 5)); // 輸出 15
return 0;
}
詳細説明
(1) va_list
-
類型:
va_list是一個類型,用於存儲可變參數列表。 -
示例:
va_list args;
(2) va_start()
-
函數原型:
void va_start(va_list ap, last_arg); -
概念實現:
// 概念性實現(實際由編譯器提供) #define va_start(ap, last_arg) \ (ap = (va_list)((char*)&last_arg + sizeof(last_arg))) -
作用:
- 初始化
va_list,使其指向可變參數列表的第一個參數。 last_arg是可變參數列表前的最後一個固定參數。
- 初始化
-
示例:
va_start(args, count);
(3) va_arg()
-
函數原型:
type va_arg(va_list ap, type); -
作用:
- 從
va_list中獲取下一個參數,並指定其類型。 type是參數的類型(如int、double等)。
- 從
-
示例:
int num = va_arg(args, int);
(4) va_end()
-
函數原型:
void va_end(va_list ap); -
作用:清理
va_list,結束可變參數列表的訪問。 -
示例:
va_end(args);
(5) va_copy()(C99 引入)
-
函數原型:
void va_copy(va_list dest, va_list src); -
作用:
- 複製一個
va_list變量。 dest是目標變量,src是源變量。
- 複製一個
-
示例:
va_list args_copy; va_copy(args_copy, args);
注意事項
- 固定參數:可變參數函數必須至少有一個固定參數(如
count),用於確定可變參數的數量或類型。 - 參數類型:使用
va_arg()時,必須明確指定參數的類型。如果類型不匹配,會導致未定義行為。 - 參數數量:需要確保訪問的參數數量不超過實際傳遞的參數數量,否則會導致未定義行為。
- 平台依賴性:可變參數列表的實現依賴於底層平台,不同平台可能有不同的行為。
更復雜的示例
以下是一個更復雜的示例,實現一個類似 printf 的函數,支持格式化輸出:
#include <stdio.h>
#include <stdarg.h>
void my_printf(const char *format, ...) {
va_list args;
va_start(args, format);
while (*format) {
if (*format == '%') {
format++; // 跳過 '%'
switch (*format) {
case 'd': {
int num = va_arg(args, int);
printf("%d", num);
break;
}
case 'f': {
double num = va_arg(args, double);
printf("%f", num);
break;
}
case 's': {
char *str = va_arg(args, char *);
printf("%s", str);
break;
}
default:
putchar(*format);
break;
}
} else {
putchar(*format);
}
format++;
}
va_end(args);
}
int main() {
my_printf("Integer: %d, Float: %f, String: %s\n", 42, 3.14, "Hello");
return 0;
}
總結
va_list是處理可變參數列表的核心類型。va_start()、va_arg()和va_end()是處理可變參數的基本宏。- 可變參數函數需要至少一個固定參數,用於確定可變參數的數量或類型。
- 使用可變參數時需要注意參數類型和數量的匹配,避免未定義行為。