修改日志类以接受字符串变量

Modify log class to accept variables in string - C++

本文关键字:字符串 变量 日志 修改      更新时间:2023-10-16

我试图修改我的日志类接受变量在我的字符串。例如,如果我想输出一个区域有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播放器在区域

有办法解决这个问题吗?

我想知道你的程序到底是怎么编译的?你用2个参数调用writeSuccess,而它被声明为只接受一个参数。

你应该看看boost格式

使用printf样式格式字符串的问题是,这些字符串

  1. 取决于所提供参数的类型
  2. 取决于所提供参数的顺序

在编写这些行时,不仅容易出错。根据我的经验,在积极维护和扩展的软件中,参数的类型和顺序很容易发生变化,而且与最初编写代码时相比,要使格式字符串与以后应用的更改保持同步要困难得多。

需要手动保持参数类型同步的问题与格式字符串可以很容易地在c++中解决,在25年前已经证明了这一点。提振。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)) );

如果你不想使用stdarg.h,这在c++中看起来不太好。你可以这样做。请记住,尽管这是一个小类(您可以添加到它中以获得更好的日志记录),但这不是最有效的方法。

#include <iostream>
#include <sstream>

class Log
{
public:
    Log() : os()
    {
    }
    ~Log()
    {
        fprintf(stderr, "%sn", 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;
}

查看标准库。

如果你不能或不会使用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)));
    //...
};

信息。注意:这是一个警告,而不是编译错误。如果你忽略警告,那是你的问题…:)