8

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

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;
}

如果我调用sumas 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,因为将 2vsum_stub中的所有值递增va_list。这当然不会编译,因为您不能获取va_arg. 还有另一种方法可以做到这一点吗?我在 C99 工作。


背景:

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

编辑:这是一个代码示例。假设我们有一个字符串foofoo是动态分配的,修改后的版本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_vprintfvprintf使用假指针的原始程序一样调用。fake_vprintf将假指针转换为真实vprintf可以使用的真实指针。

4

2 回答 2

3

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

我真的看不出有什么办法。当然,您可以创建一个原地vprintf应用转换,一次一个参数。我的建议是:重新实现所有这些标准库函数——无论如何,你正在编写包装器。这涉及到一些工作,但是您已经在使用etc 完成了其中的一部分,所以为什么不走完整个距离(并猜测函数调用上的节省!)。hc_printf

于 2010-02-05T21:15:55.183 回答
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);

You're telling the compiler that you want it to consider va_list a pointer to an int (via the int * cast), then take the value (*) and add 1000 to it (+= 1000). Now advance the va_list pointer to the next argument on the stack.

于 2010-02-05T22:01:00.830 回答