我正在尝试修改我的日志类以接受我的字符串中的变量。例如,如果我想输出一个区域中有7个玩家。
这是我写入日志功能:
void Log::writeSuccess(string text,...)
{
// Write the sucessfull operation to the logfile
logfile << "<---> " << text << endl;
}
这是我的主叫代码:
int playernum = 7;
errorLog.writeSuccess("There are %i players in the area", playernum);
它最终输出到文件:区域中有%i个玩家
有什么方法可以解决这个问题吗?
答案 0 :(得分:6)
我想知道你的程序到底是怎么编译的?!
您使用2个参数调用writeSuccess
,而声明只使用一个参数。
您应该查看boost format
答案 1 :(得分:2)
使用printf
- 样式格式字符串的问题是那些字符串是
在编写这些行时,不仅 容易出错 。根据我的经验,参数的类型和顺序很容易在主动维护和扩展的软件中发生变化,并且使格式字符串与稍后应用的更改保持同步要比在最初编写时更难实现。码。
需要 手动保持参数类型同步 的格式字符串的问题可以在C ++中轻松解决, streams 已经证明了25年前。 Boost.Format 甚至设法将格式字符串与类型安全性相结合。
我遇到的一些日志库采用了另一种解决这两个问题的方法:它们使用一种语法,您可以使用 指定要在字符串中的特定位置插入哪个参数参数的名称 ,它们使您无需考虑 参数的类型 ,方法是在插入之前将所有参数单独转换为字符串:
log( "i now has the value of @(i), current size is @(x.get_size(y))",
LOG_PARAM(i) + LOG_PARAM(x.get_size(y)) );
答案 2 :(得分:1)
如果您不想使用在c ++ IMO中看起来不太好的stdarg.h。你可以做这样的事情。请记住,尽管这是一个小类(您可以添加它以便更好地记录),但它不是最有效的方法。
#include <iostream>
#include <sstream>
class Log
{
public:
Log() : os()
{
}
~Log()
{
fprintf(stderr, "%s\n", os.str().c_str());
}
template<typename T>
std::ostringstream &operator<<(const T &t)
{
os << "Log file - " << t;
return os;
}
private:
std::ostringstream os;
};
int main(int argc, char *argv[])
{
//usage
for (int i = 0; i < 10; ++i)
Log() << "Hello world " << i;
return 0;
}
答案 3 :(得分:0)
查看stdarg标准库。它允许您处理可变数量的参数。
答案 4 :(得分:-7)
如果您不能或不会使用boost:
void Log::writeSuccess(const char* const fmt, ...) {
va_list ap;
va_start(ap, fmt);
char buff[1024];
vsnprintf(buff, sizeof(buff), fmt, ap);
logfile << buff;
}
注意:它假定书面长度有限。
更新:使用gcc可以以类型安全的方式执行此操作,您需要以下声明。
class Log {
void writeSuccess(const char* const fmt, ...) __attribute__ ((format (printf, 2, 3)));
//...
};
信息here。注意:这是一个警告,而不是编译错误。如果你忽略那些问题的警告......:)