首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

stdarg.h 可變參數完整指南:va_start/va_arg/va_end 原理與實戰

     編輯:關於C語言

標準三步驟

void demo(int fixed, ...) {
    va_list ap;
    va_start(ap, fixed);      // 1. 定位首個可變參數
    int v = va_arg(ap, int);  // 2. 按類型取參(每次調用推進)
    va_end(ap);               // 3. 清理(某些平台必須)
}

宏定義原理(x86 GCC)

typedef char *va_list;
#define va_start(ap, v) (ap = (va_list)&v + __builtin_va_arg_offset(v))
#define va_arg(ap, type) (*(type *)((ap += __builtin_va_arg_size(type)) - __builtin_va_arg_size(type)))
#define va_end(ap) (ap = (va_list)0)

本質:棧幀布局中,固定參數地址已知,可變參數緊隨其後,按類型大小遞增取值。

printf 如何實現「智能」解析?

格式字符串 "%d %s" 在運行期解析,根據格式符調用對應 va_arg(ap, int)/va_arg(ap, char*)。**C 語言本身無類型反射**,所有「智能」皆由程序員編寫解析邏輯實現。

常見陷阱與避坑

  1. 類型不匹配 UB:va_arg(ap, int) 實傳 double → 崩潰/亂碼
  2. 參數個數未知:需約定終止標記(如 NULL、-1、格式串計數)
  3. 二次遍歷:需 va_copy(dest, src) (C99) 複製 va_list
  4. 寄存器參數:ARM64/x86-64 前幾個參數在寄存器,va_start 需編譯器內建支持

實戰模板:類型安全的可變參數日誌

void log_msg(const char *fmt, ...) {
    va_list ap; va_start(ap, fmt);
    vfprintf(stderr, fmt, ap);  // vfprintf 內部安全遍歷
    va_end(ap);
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved