如何将可变数量的parameter passing给printf / sprintf
我有一个类包含一个“错误”函数,将格式化一些文本。 我想接受可变数量的参数,然后使用printf格式化它们。
例:
class MyClass { public: void Error(const char* format, ...); };
Error方法应该在参数中调用printf / sprintf来格式化,然后用它做些什么。 我不想自己编写所有的格式,所以试图找出如何使用现有的格式是有意义的。
坏
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); }
这个代码不太好。 它使用一个固定大小的字符缓冲区,如果string病态很长,会导致缓冲区溢出错误。 任意大的1024*16
大小应该在你的头上标记一个标志。 另外,如果dest
结尾包含格式代码,则printf
调用可能会遇到问题。 最好是printf("%s", dest)
。 但是更好的办法是使用vprintf
或者vfprintf
:
好
void Error(const char* format, ...) { va_list argptr; va_start(argptr, format); vfprintf(stderr, format, argptr); va_end(argptr); }
如果你想在显示之前操作string,而且确实需要先将它存储在缓冲区中,请使用vsnprintf
而不是vsprintf
。 vsnprintf
将防止意外的缓冲区溢出错误。
看看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); }
使用椭圆函数不是很安全。 如果性能对日志function不重要,请考虑使用运算符重载,如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.
我应该在堆栈溢出的现有问题上阅读更多。
C ++传递variables参数的数量是一个类似的问题。 Mike F有以下解释:
除非你想进入淘气和不可移植的技巧,否则没有办法调用(例如)printf而不知道你传递给它多less个参数。
通常使用的解决scheme是始终提供可变参数函数的替代forms,所以printf具有vprintf,它取代了va_list。… …版本只是va_list版本的封装。
这正是我所期待的。 我执行了这样的testing实现:
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); }
下面的简单例子。 注意你应该传入一个更大的缓冲区,然后testing缓冲区是否足够大
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 }
您正在寻找各种各样的function 。 printf()和sprintf()是可变参数函数 – 它们可以接受可变数目的参数。
这基本上涉及这些步骤:
-
第一个参数必须给出一些参数的指示。 所以在printf()中,“format”参数给出了这个指示 – 如果你有5个格式说明符,那么它会查找5个以上的参数(总共6个参数)。第一个参数可以是一个整数(例如“myfunction (3,a,b,c)“其中”3“表示”3个参数“
-
然后循环并检索每个连续的参数,使用va_start()等函数。
有很多关于如何做到这一点的教程 – 祝你好运!
看看这个例子http://www.cplusplus.com/reference/clibrary/cstdarg/va_arg/ ,他们将参数的数量传递给了方法,但是你可以忽略它并修改代码(见例子)。