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.
我有一个类,它包含一个“error”函数,可以格式化一些文本。我想接受可变数量的参数,然后使用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.
错误方法应该接受参数,调用printf/sprintf对其进行格式化,然后对其进行处理。我不想自己编写所有的格式,所以尝试找出如何使用现有格式是有意义的。
7 个解决方案
#1
123
Bad
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);
}
This code is not so good. It uses a fixed-size character buffer which can lead to a buffer overrun error if the string is pathologically long. The arbitrary large 1024*16
size should set off a flag in your head. Also, the printf
call could run into problems if dest
ends up containing formatting codes. Better would be printf("%s", dest)
. But even better still would be using vprintf
or vfprintf
:
这段代码不是很好。它使用一个固定大小的字符缓冲区,如果字符串是病态的长,该缓冲区可能导致缓冲区溢出错误。任意大小的1024*16应该在你的头脑中设置一个标志。而且,如果dest最后包含格式化代码,printf调用可能会遇到问题。最好是printf(“%s”,dest)。但更好的是使用vprintf或vfprintf:
Good
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, please please please use vsnprintf
instead of vsprintf
. vsnprintf
will prevent an accidental buffer overflow error.
如果您想在显示它之前操作字符串,并且确实需要先存储在缓冲区中,请使用vsnprintf而不是vsprintf。vsnprintf将防止一个偶然的缓冲区溢出错误。
#2
30
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);
}
#3
5
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.
#4
3
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:
这基本上需要这些步骤:
-
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)
第一个参数必须给出如下参数数量的一些指示。所以在printf()中,“format”参数给出了这样的指示——如果您有5个格式说明符,那么它将寻找5个更多的参数(总共6个参数)。第一个参数可以是一个整数(例如“myfunction(3, a, b, c)”,其中“3”表示3个参数)
-
Then loop through and retrieve each successive argument, using the va_start() etc. functions.
然后使用va_start()等函数循环并检索每个连续的参数。
There are plenty of tutorials on how to do this - good luck!
有很多关于如何做到这一点的教程-祝你好运!
#5
2
I should have read more on existing questions in stack overflow.
我应该在stack overflow中阅读更多关于现有问题的文章。
C++ Passing Variable Number of Arguments is a similar question. Mike F has the following explanation:
传递变量参数的c++也是一个类似的问题。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.
如果不知道要传递多少参数,就无法调用printf(例如),除非您想玩一些淘气的、不可移植的技巧。
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函数需要一个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);
}
#6
2
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
}
#7
0
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/,它们会将参数的数量传递给方法,但是您可以ommit,并适当地修改代码(参见示例)。
#1
123
Bad
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);
}
This code is not so good. It uses a fixed-size character buffer which can lead to a buffer overrun error if the string is pathologically long. The arbitrary large 1024*16
size should set off a flag in your head. Also, the printf
call could run into problems if dest
ends up containing formatting codes. Better would be printf("%s", dest)
. But even better still would be using vprintf
or vfprintf
:
这段代码不是很好。它使用一个固定大小的字符缓冲区,如果字符串是病态的长,该缓冲区可能导致缓冲区溢出错误。任意大小的1024*16应该在你的头脑中设置一个标志。而且,如果dest最后包含格式化代码,printf调用可能会遇到问题。最好是printf(“%s”,dest)。但更好的是使用vprintf或vfprintf:
Good
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, please please please use vsnprintf
instead of vsprintf
. vsnprintf
will prevent an accidental buffer overflow error.
如果您想在显示它之前操作字符串,并且确实需要先存储在缓冲区中,请使用vsnprintf而不是vsprintf。vsnprintf将防止一个偶然的缓冲区溢出错误。
#2
30
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);
}
#3
5
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.
#4
3
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:
这基本上需要这些步骤:
-
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)
第一个参数必须给出如下参数数量的一些指示。所以在printf()中,“format”参数给出了这样的指示——如果您有5个格式说明符,那么它将寻找5个更多的参数(总共6个参数)。第一个参数可以是一个整数(例如“myfunction(3, a, b, c)”,其中“3”表示3个参数)
-
Then loop through and retrieve each successive argument, using the va_start() etc. functions.
然后使用va_start()等函数循环并检索每个连续的参数。
There are plenty of tutorials on how to do this - good luck!
有很多关于如何做到这一点的教程-祝你好运!
#5
2
I should have read more on existing questions in stack overflow.
我应该在stack overflow中阅读更多关于现有问题的文章。
C++ Passing Variable Number of Arguments is a similar question. Mike F has the following explanation:
传递变量参数的c++也是一个类似的问题。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.
如果不知道要传递多少参数,就无法调用printf(例如),除非您想玩一些淘气的、不可移植的技巧。
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函数需要一个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);
}
#6
2
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
}
#7
0
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/,它们会将参数的数量传递给方法,但是您可以ommit,并适当地修改代码(参见示例)。