C語言可變引數函數

2020-07-16 10:04:19
C 語言允許定義引數數量可變的函數,這稱為可變引數函數(variadic function)。這種函數需要固定數量的強制引數(mandatory argument),後面是數量可變的可選引數(optional argument)。

這種函數必須至少有一個強制引數。可選引數的型別可以變化。可選引數的數量由強制引數的值決定,或由用來定義可選參數列的特殊值決定。

C 語言中最常用的可變引數函數例子是 printf()和 scanf()。這兩個函數都有一個強制引數,即格式化字串。格式化字串中的轉換修飾符決定了可選引數的數量和型別。

對於每一個強制引數來說,函數頭部都會顯示一個適當的引數,像普通函數宣告一樣。參數列的格式是強制性引數在前,後面跟著一個逗號和省略號(...),這個省略號代表可選引數。

可變引數函數要獲取可選引數時,必須通過一個型別為 va_list 的物件,它包含了引數資訊。這種型別的物件也稱為引數指標(argument pointer),它包含了棧中至少一個引數的位置。可以使用這個引數指標從一個可選引數移動到下一個可選引數,由此,函數就可以獲取所有的可選引數。va_list 型別被定義在標頭檔案 stdarg.h 中。

當編寫支援引數數量可變的函數時,必須用 va_list 型別定義引數指標,以獲取可選引數。在下面的討論中,va_list 物件被命名為 argptr。可以用 4 個宏來處理該引數指標,這些宏都定義在標頭檔案 stdarg.h 中:
void va_start(va_list argptr, lastparam);

宏 va_start 使用第一個可選引數的位置來初始化 argptr 引數指標。該宏的第二個引數必須是該函數最後一個有名稱引數的名稱。必須先呼叫該宏,才可以開始使用可選引數。
type va_arg(va_list argptr, type);

展開宏 va_arg 會得到當前 argptr 所參照的可選引數,也會將 argptr 移動到列表中的下一個引數。宏 va_arg 的第二個引數是剛剛被讀入的引數的型別。
void va_end(va_list argptr);

當不再需要使用引數指標時,必須呼叫宏 va_end。如果想使用宏 va_start 或者宏 va_copy 來重新初始化一個之前用過的引數指標,也必須先呼叫宏 va_end。
void va_copy(va_list dest, va_list src);

宏 va_copy 使用當前的 src 值來初始化引數指標 dest。然後就可以使用 dest 中的備份獲取可選參數列,從 src 所參照的位置開始。

例 1 中的函數展示了這些宏的使用方法。

【例1】函數 add()
// 函數add() 計算可選引數之和
// 引數:第一個強制引數指定了可選引數的數量,可選引數為double型別
// 返回值:和值,double型別
double add( int n, ... )
{
  int i = 0;
  double sum = 0.0;
  va_list argptr;
  va_start( argptr, n );             // 初始化argptr
  for ( i = 0; i < n; ++i )       // 對每個可選引數,讀取型別為double的引數,
    sum += va_arg( argptr, double ); // 然後累加到sum中
  va_end( argptr );
  return sum;
}