如何将可变数量的参数传递给printf / sprintf

时间:2009-06-29 03:11:11

标签: c++ c printf variadic-functions

我有一个类,它包含一个“错误”函数,可以格式化一些文本。我想接受可变数量的参数,然后使用printf格式化它们。

示例:

class MyClass
{
public:
    void Error(const char* format, ...);
};

Error方法应该接受参数,调用printf / sprintf来格式化它然后用它做一些事情。我不想自己编写所有格式,因此尝试找出如何使用现有格式是有意义的。

7 个答案:

答案 0 :(得分:136)

void Error(const char* format, ...)
{
    va_list argptr;
    va_start(argptr, format);
    vfprintf(stderr, format, argptr);
    va_end(argptr);
}

如果您想在显示字符串之前对其进行操作,并且确实需要先将其存储在缓冲区中,请使用 vsnprintf 而不是vsprintfvsnprintf将防止意外的缓冲区溢出错误。

答案 1 :(得分:31)

看看vsnprintf,因为这会做你想要的http://www.cplusplus.com/reference/clibrary/cstdio/vsprintf/

首先必须初始化va_list arg数组,然后调用它。

该链接的示例: / * vsprintf示例* /

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

void Error (char * format, ...)
{
  char buffer[256];
  va_list args;
  va_start (args, format);
  vsnprintf (buffer, 255, format, args);


  //do something with the error

  va_end (args);
}

答案 2 :(得分:5)

使用椭圆函数不是很安全。如果性能对于日志函数并不重要,请考虑使用boost :: format中的运算符重载。你可以这样写:

#include <sstream>
#include <boost/format.hpp>
#include <iostream>
using namespace std;

class formatted_log_t {
public:
    formatted_log_t(const char* msg ) : fmt(msg) {}
    ~formatted_log_t() { cout << fmt << endl; }

    template <typename T>
    formatted_log_t& operator %(T value) {
        fmt % value;
        return *this;
    }

protected:
    boost::format                fmt;
};

formatted_log_t log(const char* msg) { return formatted_log_t( msg ); }

// use
int main ()
{
    log("hello %s in %d-th time") % "world" % 10000000;
    return 0;
}

以下示例演示了省略号的可能错误:

int x = SOME_VALUE;
double y = SOME_MORE_VALUE;
printf( "some var = %f, other one %f", y, x ); // no errors at compile time, but error at runtime. compiler do not know types you wanted
log( "some var = %f, other one %f" ) % y % x; // no errors. %f only for compatibility. you could write %1% instead.

答案 3 :(得分:3)

我应该阅读有关堆栈溢出的现有问题的更多信息。

C++ Passing Variable Number of Arguments是一个类似的问题。 Mike F有以下解释:

  

无法调用(例如)printf   不知道有多少论点   你要传递给它,除非你想要   进入顽皮和不便携   技巧。

     

通常使用的解决方案是   总是提供另一种形式   vararg函数,所以printf有   将va_list放在适当位置的vprintf   ...... ......版本只是   va_list版本周围的包装器。

这正是我想要的。我执行了这样的测试实现:

void Error(const char* format, ...)
{
    char dest[1024 * 16];
    va_list argptr;
    va_start(argptr, format);
    vsprintf(dest, format, argptr);
    va_end(argptr);
    printf(dest);
}

答案 4 :(得分:3)

您正在寻找variadic functions。 printf()和sprintf()是可变参数函数 - 它们可以接受可变数量的参数。

这基本上需要这些步骤:

  1. 第一个参数必须指示后面的参数数量。所以在printf()中,“format”参数给出了这个指示 - 如果你有5个格式说明符,那么它将寻找另外5个参数(总共6个参数。)第一个参数可以是一个整数(例如“myfunction”) (3,a,b,c)“where”3“表示”3个参数“

  2. 然后使用va_start()等函数循环并检索每个连续的参数。

  3. 有很多关于如何做到这一点的教程 - 祝你好运!

答案 5 :(得分:2)

以下简单示例。请注意,您应该传入更大的缓冲区,并测试缓冲区是否足够大

void Log(LPCWSTR pFormat, ...) 
{
    va_list pArg;
    va_start(pArg, pFormat);
    char buf[1000];
    int len = _vsntprintf(buf, 1000, pFormat, pArg);
    va_end(pArg);
    //do something with buf
}

答案 6 :(得分:0)

看看示例http://www.cplusplus.com/reference/clibrary/cstdarg/va_arg/,它们将参数的数量传递给方法,但您可以省略并适当地修改代码(参见示例)。