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

C語言可變參數格式化 I/O 函數參考(V 開頭函數)

     編輯:關於C語言

C語言 V 開頭函數詳解:vprintf、vfprintf、vsprintf、vscanf、vfscanf、vsscanf

本文介紹 可變參數清單 版本的格式化輸入/輸出函數族群。這些函數接受 va_list 而非可變參數,適合建立自訂格式化包裝函數 (如日誌、除錯巨集)。

核心概念:va_list 與三巨頭巨集

#include <stdarg.h>

void my_printf(const char *fmt, ...) {
    va_list ap;
    va_start(ap, fmt);     // 初始化
    vprintf(fmt, ap);      // 核心處理
    va_end(ap);            // 清理
}

輸出函數族

函數輸出目的地原型
vprintfstdoutint vprintf(const char *fmt, va_list ap);
vfprintfFILE *streamint vfprintf(FILE *fp, const char *fmt, va_list ap);
vsprintfchar *bufferint vsprintf(char *buf, const char *fmt, va_list ap);

vsprintf 安全性警告:不檢查緩衝區長度,易造成緩衝區溢位。C99 提供 vsnprintf(buf, size, fmt, ap) 限制長度,請優先使用。

輸入函數族

函數輸入來源原型
vscanfstdinint vscanf(const char *fmt, va_list ap);
vfscanfFILE *streamint vfscanf(FILE *fp, const char *fmt, va_list ap);
vsscanfchar *stringint vsscanf(const char *buf, const char *fmt, va_list ap);

完整範例:自訂日誌函數同時寫入螢幕與檔案

#include <stdio.h>
#include <stdarg.h>
#include <time.h>

FILE *logfp = NULL;

void log_init(const char *path) {
    logfp = fopen(path, "a");
}

void log_msg(const char *fmt, ...) {
    va_list ap;
    char buf[256];
    time_t now = time(NULL);
    struct tm *t = localtime(&now);

    va_start(ap, fmt);
    vsnprintf(buf, sizeof(buf), fmt, ap); // 安全格式化
    va_end(ap);

    printf("[%02d:%02d:%02d] %s\n", t->tm_hour, t->tm_min, t->tm_sec, buf);
    if (logfp) {
        fprintf(logfp, "[%02d:%02d:%02d] %s\n", t->tm_hour, t->tm_min, t->tm_sec, buf);
        fflush(logfp);
    }
}

int main(void) {
    log_init("app.log");
    log_msg("System started, version %d.%d", 1, 0);
    log_msg("User %s logged in", "admin");
    fclose(logfp);
    return 0;
}

掃描範例:從字串解析多欄位資料

char line[] = "42 3.14 hello";
int a; float b; char c[20];
va_list ap;
va_start(ap, c); // 僅示意,實際需包裝函數
vsscanf(line, "%d %f %s", ap); // 需自行建立 va_list
/* 正確寫法見下方包裝函數 */

正確包裝 vsscanf:

int scan_string(const char *src, const char *fmt, ...) {
    va_list ap;
    int n;
    va_start(ap, fmt);
    n = vsscanf(src, fmt, ap);
    va_end(ap);
    return n;
}

/* 使用 */
scan_string(line, "%d %f %s", &a, &b, c);

重點提醒:

  1. va_list 在函數間傳遞時屬「一次性」使用,若需多次掃描,必須用 va_copy (C99) 複製副本。
  2. 所有 v*printf 回傳輸出字元數 (不含結尾 null);v*scanf 回傳成功轉換項目數或 EOF。
  3. 現代程式碼宜改用 vsnprintf、vswprintf (寬字元) 等安全版本。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved