操纵可变参数的标准方法?

时间:2010-02-05 20:59:32

标签: c variadic-functions

这是一个奇怪的问题,但在将va_list的内容传递给另一个函数之前是否有一种标准的方法来操作它?例如,假设我有两个函数sumvsum

int vsum(int n, va_list ap) {
    int total = 0;
    for (int i = 0; i < n; ++i) {
        total += va_arg(n, int);
    return total;
}

int sum(int n, ...) {
    va_list ap;
    va_start(ap, n);
    int total = vsum(n, ap);
    va_end(ap);
    return total;
}

如果我将sum称为sum(4, 1, 2, 3, 4),我希望得到结果10.现在让我们假设不是直接调用vsum,而是sum调用中间函数, vsum_stub执行以下操作:

int vsum_stub(int n, va_list ap) {
    va_list temp_ap;
    va_copy(temp_ap, ap);
    for (int i = 0; i < n; ++i) {
        int *arg = &va_arg(ap, int);
        *arg += 2;
    }
    va_end(temp_ap);
    return vsum(n, ap);
}

现在当我调用sum(4, 1, 2, 3, 4)时,我应该返回结果20,因为vsum_stubva_list中的所有值递增2.当然,这不会编译你不能取va_arg结果的地址。有没有另外一种方法可以做到这一点?我在C99工作。


背景

我正在开发一个可以进行指针转换的库,这样数据就可以以更高效的格式存储在堆上。程序使用自定义转换进行编译,该转换将对printf等库函数的调用转换为我自己的存根函数(例如hc_printf)。在将参数传递给真正的hc_printf函数之前,%s需要翻译任何指针参数(用于printf的字符串)。

编辑:这是一个代码示例。假设我们有一个字符串foo。使用foo的修改版本动态分配malloc,该版本返回假指针。编译器修改程序,以便它可以处理假指针。所以这有效:

char *foo = fake_malloc(4);
fake_strcpy(foo, "foo");

我想写一个这样的fake_vprintf函数(在伪代码中):

int fake_vprintf(const char *format, va_list args) {
    for each pointer argument p in args
        translate p to q, a real pointer to contiguous memory
        replace p with q in args
    }
    return vprintf(format, args);
}

该程序将使用假指针调用fake_vprintf,就像原始vprintf一样。 fake_vprintf将假指针转换为真实vprintf可以使用的真实指针。

2 个答案:

答案 0 :(得分:3)

您可能无法以与平台无关的方式使用va_list。您必须查看您的环境如何在stdarg.h中定义va_list,然后编写自己的工具来使用它。

例如,如果va_list只是一个(char *),你可以用它做各种各样的事情。

// add 1000 to the integer stored on the stack and advance va_list
*(int *)va_list += 1000;
va_list += sizeof(int);

您告诉编译器您希望它考虑va_list指向int的指针(通过int * cast),然后取值(*)并向其添加1000(+ = 1000)。现在将va_list指针前进到堆栈上的下一个参数。

答案 1 :(得分:2)

啊哈,据我所知,你的问题是创建一个新的va_list参数,以传递给标准的vprintf函数。反过来,这将要求您修改列表中的每个成员。但是,由于没有针对此类列表的元素明智的提取/编辑/插入操作,因此您将被卡住。

我真的没有办法做到这一点。当然,您可以创建vprintf一次应用转换 in situ ,一个参数。我的建议是:重新实现所有这样的标准库函数 - 无论如何你正在编写包装器。这涉及一些工作,但你已经用hc_printf等做了一部分工作,所以为什么不去整个距离(并猜测函数调用的节省!)。