代码之家  ›  专栏  ›  技术社区  ›  Jay Conrod

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

  •  7
  • Jay Conrod  · 技术社区  · 16 年前

    这是一个奇怪的问题,但是有没有一种标准的方法来操纵 va_list 在传递给另一个函数之前?例如,假设我有两个函数, 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;
    }
    

    如果我打电话 总和 作为 sum(4, 1, 2, 3, 4) 我希望得到结果10。现在让我们假设不是打电话 会计凭证汇总系统 直接地, 总和 调用中间函数, 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);
    }
    

    现在当我呼唤 总和(4,1,2,3,4) ,我应该把结果20拿回来,因为 VSUME短截线 将中的所有值递增 VAI表 按2。当然,这不会编译,因为您不能获取 va_arg .不过,还有别的办法吗?我在C99工作。


    背景:

    我正在开发一个库,它执行一些指针转换,以便以更有效的格式将数据存储在堆中。程序是用自定义转换编译的,该转换将调用转换为库函数,例如 printf 到我自己的存根函数(例如, hc_printf ) HCP-Primtf 需要转换任何指针参数(用于 %s )在将参数传递给real之前 普林特 功能。

    编辑: 下面是一个代码示例。假设我们有一根绳子 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);
    }
    

    程序会调用 法基 就像原版一样 vprintf 使用假指针。 法基 将假指针转换为 VPrTNF 可以使用。

    2 回复  |  直到 16 年前
        1
  •  2
  •   dirkgently    16 年前

    啊哈,据我所知,你的问题是创造一个新的 va_list 传递给标准的参数 vprintf 功能。反过来,将要求您修改列表中的每个成员。但是,由于没有针对此类列表的元素方面的fetch/edit/insert操作,因此您被卡住了。

    我真的看不出有什么办法能做到这一点。当然,您可以创建一个 VPrTNF 应用转换 就地 一次一个论点。我的建议是:重新实施 全部的 这样的标准库函数——无论如何,您正在编写包装器。这涉及到一些工作,但你已经在做其中的一部分了 hc_printf 等等,为什么不走完全程(猜猜函数调用节省了什么!).

        2
  •  3
  •   tomlogic    16 年前

    你可能不能以平台不可知的方式使用va_列表。您必须了解您的环境如何在stdarg.h中定义一个va_列表,然后编写自己的工具来使用它。

    例如,如果一个va_列表只是一个(char*),您可以用它做各种事情。

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

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