首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C 語言可變參數函數實現平均值計算:va_list 完整用法與調用示例

     編輯:程式設計綜合問答

需求

編寫函數 `float avg(int n, ...)` 接收不定數量整數參數,返回平均值。主函數調用 `avg(5, 1, 2, 3, 4, 5)` 輸出 `3.000000`。

標準實現 ()

#include 
#include 

float avg(int n, ...) {
    va_list ap;
    va_start(ap, n); // 初始化,n 為最後一個固定參數
    
    int sum = 0;
    for (int i = 0; i < n; i++) {
        int val = va_arg(ap, int); // 依次提取 int 參數
        sum += val;
    }
    
    va_end(ap); // 清理
    return (float)sum / n;
}

int main() {
    float result = avg(5, 1, 2, 3, 4, 5);
    printf("平均值 = %.6f\n", result); // 3.000000
    return 0;
}

關鍵宏解析

宏作用注意事項
`va_list ap` 聲明參數列表指針 不透明類型,僅配合三宏使用
`va_start(ap, last_fixed)` 定位到第一個可變參數 `last_fixed` 必須是最後一個**命名**參數 (此處為 `n`)
`va_arg(ap, type)` 按 `type` 提取下一個參數,並推進指針 **調用者必須保證類型匹配**,否則 UB (如傳 `double` 卻 `va_arg(ap, int)`)
`va_end(ap)` 釋放資源 (某些平台需棧指針恢復) **必須成對調用**,函數所有返回路徑均需執行
`va_copy(dest, src)` (C99) 複製參數列表狀態,支持二次遍歷 複製後需各自 `va_end`

進階:類型安全封裝 (C11 `_Generic` / GCC 擴展)


// GCC/Clang 格式化屬性檢查 (編譯期警告類型不匹配)
float avg_checked(int n, ...) __attribute__((format(printf, 2, 0))); 
// 實際仍需 va_arg 手動提取,屬性僅檢查格式字符串場景

// C11 _Generic 實現類型多態 (示例:支持 int/double 混合)
#define AVG(...) _Generic((__VA_ARGS__), \
    int: avg_int, \
    double: avg_double \
)(__VA_ARGS__) // 需配合可變參數宏技巧,較複雜

常見錯誤避坑

  1. 忘記 `va_end`:導致棧損壞、內存洩漏 (部分架構)。
  2. 參數個數 `n` 與實際傳入不符:多讀越界、少讀遺漏,**無運行時檢查機制**,需約定俗成 (如首參數指定個數、哨兵值 -1、格式字符串)。
  3. 類型不匹配:`va_arg(ap, int)` 讀取 `float`/`double` 會觸發默認參數提升規則導致錯誤解讀。
    規則:`float` → `double`,`char`/`short` → `int`。傳 `float` 必須 `va_arg(ap, double)`。
  4. 可變參數不能為引用/非 POD 類型:C++ 類對象傳遞需用 `std::initializer_list`、`std::variant`、參數包模板 (C++11)。

C++ 現代替代方案


// C++11 參數包模板 (類型安全、編譯期展開、零開銷)
template
double avg_cpp(Args... args) {
    static_assert(sizeof...(Args) > 0, "至少一個參數");
    double sum = (0.0 + ... + args); // 折疊表達式
    return sum / sizeof...(Args);
}

// 調用
avg_cpp(1, 2, 3, 4, 5);        // 3.0
avg_cpp(1.5, 2.5, 3.0);        // 2.333...
// avg_cpp("str");              // 編譯錯誤:非算術類型
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved