c++ 如何向printf/sprintf传递可变数量的参数

vjhs03f7  于 2022-12-30  发布在  其他
关注(0)|答案(7)|浏览(249)

我有一个类,其中包含一个"error"函数,该函数将格式化一些文本。我希望接受可变数量的参数,然后使用printf化它们。

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

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

tmb3ates

tmb3ates1#

使用vfprintf,如下所示:

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

这会将结果输出到stderr。如果要将输出保存为字符串而不是显示它,请使用vsnprintf。(避免使用vsprintf:由于它不知道输出缓冲区的大小,因此容易发生缓冲区溢出。)

wqlqzqxt

wqlqzqxt2#

请看一下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);
}
8ulbf1ek

8ulbf1ek3#

我应该多读一些关于堆栈溢出的现有问题。
C++ Passing Variable Number of Arguments是一个类似的问题,Mike F有如下解释:
如果不知道要传递多少参数,就无法调用(eg)printf,除非你想使用一些不好用的、不可移植的技巧。
通常使用的解决方案是始终提供vararg函数的替代形式,因此printf有vprintf,它用va_list代替......版本只是va_list版本的 Package 器。
这正是我一直在寻找的。我执行了一个测试实现,如下所示:

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

rks48beu4#

您正在寻找variadic functions。printf()和sprintf()是可变参数函数-它们可以接受可变数量的参数。
这基本上包括以下步骤:
1.第一个参数必须给予后面参数的数目,所以在printf()中,“format”参数给出了这个指示--如果你有5个格式说明符,那么它将寻找另外5个参数(总共6个参数)。第一个参数可以是整数(例如“myfunction(3,a,b,c)”,其中“3”表示“3个参数”)
1.然后使用va_start()等函数循环并检索每个连续的参数。
关于如何做到这一点有很多教程-祝你好运!

pqwbnv8z

pqwbnv8z5#

下面是一个简单的例子。注意,你应该传入一个更大的缓冲区,然后测试这个缓冲区是否足够大

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

v1l68za46#

使用带省略号的函数不是很安全。如果log函数的性能不是很重要,可以考虑使用boost::格式的运算符重载。你可以写这样的代码:

#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.
kyxcudwk

kyxcudwk7#

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

相关问题