You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++中printf包装器如何传递参数包至make_buffer_fmt?

解决printf包装函数的可变参数传递问题

要解决你遇到的参数包传递问题,核心是为每个可变参数函数提供对应的va_list重载版本,这样既能保留直接传可变参数的便捷性,又能避免重复写va_start/va_end的样板代码,同时解决非法传递va_list导致的内存读取错误。

步骤1:为make_buffer_fmt添加va_list版本

先实现接收va_list的底层函数,原可变参数版本调用这个函数,复用核心逻辑:

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 底层va_list版本,负责实际的缓冲区构建
char* make_buffer_fmt_va(char foo, const char* fmt, va_list va) {
    // 先计算所需缓冲区大小
    va_list va_copy;
    va_copy(va_copy, va);
    int size = vsnprintf(NULL, 0, fmt, va_copy);
    va_end(va_copy);

    if (size < 0) return NULL;
    char* buf = malloc(size + 1);
    if (!buf) return NULL;

    vsnprintf(buf, size + 1, fmt, va);
    return buf;
}

// 原可变参数版本,保留便捷调用方式
char* make_buffer_fmt(char foo, const char* fmt, ...) {
    va_list va;
    va_start(va, fmt);
    char* buf = make_buffer_fmt_va(foo, fmt, va);
    va_end(va);
    return buf;
}

步骤2:为write_fmt添加va_list版本

同样拆分出va_list版本,原可变参数版本调用它,同时让va_list版本复用make_buffer_fmt_va:

#include <unistd.h>

// va_list版本的write_fmt,供上层函数传递参数包
int write_fmt_va(int fd, char foo, const char* fmt, va_list va) {
    char* buf = make_buffer_fmt_va(foo, fmt, va);
    if (!buf) return -1;

    int ret = write(fd, buf, strlen(buf));
    free(buf);
    return ret;
}

// 原可变参数版本,支持直接调用如write_fmt(fd, foo, "Hello %s", "World")
int write_fmt(int fd, char foo, const char* fmt, ...) {
    va_list va;
    va_start(va, fmt);
    int ret = write_fmt_va(fd, foo, fmt, va);
    va_end(va);
    return ret;
}

步骤3:实现简洁的log函数

现在log函数只需处理自身的va_list,调用write_fmt_va即可,无需重复冗余代码:

#define LOG_FILENO STDOUT_FILENO
#define LOG_INFO 'I'

int log_info(const char* fmt, ...) {
    va_list va;
    va_start(va, fmt);
    int ret = write_fmt_va(LOG_FILENO, LOG_INFO, fmt, va);
    va_end(va);
    return ret;
}

关键说明

  • 你之前的错误在于直接将va_list传给可变参数...:write_fmt的...期望的是可变参数列表,而非va_list对象,这样传递会导致函数错误地把va_list当作普通参数解析,进而读取随机内存。
  • 拆分出va_list版本后,所有上层函数只需做一次va_start/va_end,底层逻辑复用va版本实现,彻底消除重复样板。
  • 保留原可变参数版本,依然支持直接调用write_fmt(LOG_FILENO, LOG_INFO, "Hello %s", "World")的便捷写法。

内容的提问来源于stack exchange,提问作者mj2

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 12:55:15