▌第一次閱讀本系列的,可以先看:


▌可變參數函數:

需要 #include <stdarg.h> 。
包括一個類型,四個巨集函數
類型: va_list ,用來儲存巨集va_arg()與巨集va_end()所需資訊
巨集函數: va_start()va_arg()va_end()va_copy()
除了 va_copy() 是 C99 外,其餘都是相容於 C89 。

▌用法例子:

int sum(int num, ...){
    
    va_list args;
    va_start(args, num);
    
    int sum = 0;
    for(i = 0; i < num; i++){
        sum += va_arg(args, int);
    }
    
    va_end(args);
    
    return sum;
}
先創建一個 va_list 類型的變數,
va_start() 有兩個參數,第一個是剛剛宣告的變數( va_list 類型),
第二個是 可變參數 ... 前一個的變數名,這裏是 num 。
va_arg() 用於獲得額外參數的數值,同樣有兩個參數,
第一個也是剛剛宣告的變數,第二個是 載入的參數類型
注意 載入的參數類型 不可為
  • char、signed char、unsigned char
  • short、unsigned short
  • signed short、short int、signed short int、unsigned short int
  • float
va_end() ,像 fclose() 一樣把可變參數關掉。
一個參數,va_list 類型的變數。

▌可變參數宏 VA_ARGS :

由 C99 引入,
聲明語法類似於可變參數函數:逗號後面三個句點"...",表示一個或多個參數。
但常見編譯器也允許傳遞0個參數。
宏擴展時使用特殊標識符__VA_ARGS__表示所傳遞的參數的替換。
沒辦法訪問可變參數列表內的單個參數,也不能獲知多少個參數被傳遞。
例子:
#define foo(f, ...) printf(f, __VA_ARGS__)
foo("%d%d", x, y); 等價 printf("%d%d", x, y);
接收了兩個額外參數。
注意 沒辦法訪問可變參數列表內的單個參數,也不能獲知多少個參數被傳遞。
所以不能夠像可變參數函數一樣,
可以以“簡單直觀”的方法去實現可變參數的 sum()。

▌額外的逗號:

若果額外參數的數目為 0 ,即 foo("123"); ,
會被展開為 printf("123",) ,這裏出現了一個額外的逗號
可把 __VA_ARGS__ 改為 ##__VA_ARGS__ ,
去提示編譯器,會自動把逗號去除。
Visual C++ 貌似不用提醒也會自動去除。

▌參考資料:

stdarg.h - 維基百科,自由的百科全書
https://zh.wikipedia.org/wiki/Stdarg.h
可变参数函数详解 - clover_toeic - 博客园
https://www.cnblogs.com/clover-toeic/p/3736748.html