链接可变参数函数调用

时间:2019-04-14 08:35:46

标签: c++ c variadic-functions

从具有可变参数数量的函数进行的printf类调用很容易进行-只需使用这些函数的 v 版本(vprintf vsprintfCString::FormatV等)。但是,如果我将呼叫链接起来怎么办?这是简单的代码:

#include <stdarg.h>
#include <iostream>
void direct(const char * _fmt, bool _extra, ...){
    va_list args;
    va_start(args, _extra);

    char ca[200];
    vsprintf(ca, _fmt, args);
    std::cout << ca << std::endl;

    va_end(args);
}

void chained(const char * _fmt, ...){
    va_list args;
    va_start(args, _fmt);
    direct(_fmt, false, args);
    va_end(args);
}

int main(){
    direct("direct works just fine: %d", false, 1);
    chained("indirect produces garbage: %d", 1);
    return 0;
}

示例输出如下:

direct works just fine: 1
indirect produces garbage: 1951661256

我觉得我缺少明显的东西,但到目前为止还无法弄清楚。请帮我修复它,以便无论我叫direct还是chained都可以正常工作。

将问题标记为C / C ++,但我更喜欢C ++答案(如果有所不同)

2 个答案:

答案 0 :(得分:5)

  

我觉得我缺少明显的东西,但到目前为止还无法弄清

您做到了。这实际上是您开始的:“只需使用这些功能的v版本” 。这些函数获得v版本的原因是允许将它们链接起来,就像您所说的那样。因此,如果您想为自己的类似于printf的功能支持它,请确保遵循相同的做法:

void direct_v(const char * _fmt, bool _extra, va_list args){
    char ca[200];
    vsprintf(ca, _fmt, args);
    std::cout << ca << std::endl;
}

void direct(const char * _fmt, bool _extra...){
    va_list args;
    va_start(args, _extra);
    direct_v(_fmt, _extra, args);
    va_end(args);
}

void chained(const char * _fmt...){
    va_list args;
    va_start(args, _fmt);
    direct_v(_fmt, false, args);
    va_end(args);
}

像这样拆分direct的一个很好的新兴属性是,您可以更好地分离关注点。包装器执行va_list相关位,而v函数仅关心列表需要完成的操作,因此可以在此处重用。


预编辑说明:顺便说一句,如果确实需要C兼容性,则函数原型需要使用逗号将最后一个参数与省略号分开。您使用的语法仅是C ++。

答案 1 :(得分:0)

不能链式调用C风格的可变参数函数。唯一的方法是将va_list作为参数传递。这正是需要v *系列功能的原因。

因此,您可以根据va_list编写类似v *的函数,然后然后将每个函数包装在基于省略号的可变参数函数中。