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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1056411/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 18:35:51  来源:igfitidea点击:

How to pass variable number of arguments to printf/sprintf

c++cprintfvariadic-functions

提问by user5722

I have a class that holds an "error" function that will format some text. I want to accept a variable number of arguments and then format them using printf.

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

Example:

例子:

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

The Error method should take in the parameters, call printf/sprintf to format it and then do something with it. I don't want to write all the formatting myself so it makes sense to try and figure out how to use the existing formatting.

Error 方法应该接收参数,调用 printf/sprintf 对其进行格式化,然后对其进行处理。我不想自己编写所有格式,因此尝试弄清楚如何使用现有格式是有意义的。

回答by John Kugelman

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

If you want to manipulate the string before you display it and really do need it stored in a buffer first, use vsnprintfinstead of vsprintf. vsnprintfwill prevent an accidental buffer overflow error.

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

回答by Lodle

have a look at vsnprintf as this will do what ya want http://www.cplusplus.com/reference/clibrary/cstdio/vsprintf/

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

you will have to init the va_list arg array first, then call it.

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

Example from that link: /* vsprintf example */

该链接中的示例:/* 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);
}

回答by user5722

I should have read more on existing questions in stack overflow.

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

C++ Passing Variable Number of Argumentsis a similar question. Mike F has the following explanation:

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

There's no way of calling (eg) printf without knowing how many arguments you're passing to it, unless you want to get into naughty and non-portable tricks.

The generally used solution is to always provide an alternate form of vararg functions, so printf has vprintf which takes a va_list in place of the .... The ... versions are just wrappers around the va_list versions.

在不知道传递给它的参数数量的情况下,没有办法调用(例如) printf ,除非您想使用顽皮和不可移植的技巧。

通常使用的解决方案是始终提供可变参数函数的替代形式,因此 printf 具有 vprintf,它采用 va_list 代替 .... ... 版本只是 va_list 版本的包装器。

This is exactly what I was looking for. I performed a test implementation like this:

这正是我正在寻找的。我执行了这样的测试实现:

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

回答by Kirill V. Lyadvinsky

Using functions with the ellipses is not very safe. If performance is not critical for log function consider using operator overloading as in boost::format. You could write something like this:

使用带有省略号的函数不是很安全。如果性能对日志功能不是很重要,请考虑使用如 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;
}

The following sample demonstrates possible errors with ellipses:

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

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.

回答by poundifdef

You are looking for variadic functions. printf() and sprintf() are variadic functions - they can accept a variable number of arguments.

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

This entails basically these steps:

这基本上需要以下步骤:

  1. The first parameter must give some indication of the number of parameters that follow. So in printf(), the "format" parameter gives this indication - if you have 5 format specifiers, then it will look for 5 more arguments (for a total of 6 arguments.) The first argument could be an integer (eg "myfunction(3, a, b, c)" where "3" signifies "3 arguments)

  2. Then loop through and retrieve each successive argument, using the va_start() etc. functions.

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

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

There are plenty of tutorials on how to do this - good luck!

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

回答by DougN

Simple example below. Note you should pass in a larger buffer, and test to see if the buffer was large enough or not

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

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
}

回答by stefanB

Have a look at the example http://www.cplusplus.com/reference/clibrary/cstdarg/va_arg/, they pass the number of arguments to the method but you can ommit that and modify the code appropriately (see the example).

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