修改日志类以接受字符串中的变量 - C++

发布于 2024-11-26 20:03:45 字数 444 浏览 0 评论 0原文

我正在尝试修改我的日志类以接受字符串中的变量。例如,如果我想输出一个区域中有 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 个玩家

有办法解决这个问题吗?

I am trying to modify my log class to accept variables in my string. For example, if I wanted to output that there are 7 players in an area.

Here is my write to log function:

void Log::writeSuccess(string text,...)
{
    // Write the sucessfull operation to the logfile
    logfile << "<---> " << text << endl;
}

And here is my calling code:

int playernum = 7;

errorLog.writeSuccess("There are %i players in the area", playernum);

It just ends up outputting to the file: There are %i players in the area

Any way to fix this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

遇到 2024-12-03 20:03:45

我想知道你的程序到底是如何编译的?!
您使用 2 个参数调用 writeSuccess,而它被声明为仅采用一个参数。

您应该查看 Boost 格式

I wonder how on earth does your program even compile?!
You call writeSuccess with 2 arguments, whereas it is declared to take only one argument.

You should look at boost format

云巢 2024-12-03 20:03:45

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

  1. 依赖于所提供参数的类型,并且
  2. >取决于所提供参数的顺序

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

需要手动保持参数类型与格式字符串同步的问题可以在 C++、Boost.Format 甚至设法将格式字符串与类型安全结合起来。

我见过的一些日志库采用了一种不同的方法来解决这两个问题:它们使用一种语法,您可以使用参数名称<来指定要在字符串中的特定位置插入哪个参数。 /em>,并且它们在插入参数之前将所有参数单独转换为字符串,从而使您不必考虑参数的类型

log( "i now has the value of @(i), current size is @(x.get_size(y))", 
     LOG_PARAM(i) + LOG_PARAM(x.get_size(y)) );

The problem with using printf-style format strings is that those strings are

  1. dependent on the types of the provided arguments, and
  2. dependent on the order of the provided arguments.

Not only is this error-prone when you are writing those lines. In my experience the types and order of the arguments will easily change in software that is actively maintained and extended, and it's much harder still to keep the format strings in sync with changes applied later, than it is to do so when you initially write the code.

The problem of needing to manually keep the parameter types in sync with the format string can easily be solved in C++, streams have proven that 25 years ago. Boost.Format even manages to combine format strings with type safety.

A different approach, solving both problems, is taken by some logging libraries I have seen: They use a syntax where you specify which parameter is to be inserted at a specific place in a string by using the parameter's name, and they free you from having to think about the parameter's type by individually converting all parameters to strings before inserting them:

log( "i now has the value of @(i), current size is @(x.get_size(y))", 
     LOG_PARAM(i) + LOG_PARAM(x.get_size(y)) );
请别遗忘我 2024-12-03 20:03:45

如果你不想使用 stdarg.h ,它在 C++ IMO 中看起来不太好。你可以做这样的事情。请记住,虽然这是一个小类(您可以添加它以更好地记录日志),但这并不是最有效的方法。

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

If you don't want to use stdarg.h which doesn't look good in c++ IMO. you can do something like this. Keep in mind that although this is a small class (you can add to it for better logging), its not the most efficient way to do it.

#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;
}
无需解释 2024-12-03 20:03:45

查看 stdarg 标准库。它允许您处理可变数量的参数。

Look at stdarg standard library. It allows you to handle variable number of parameters.

涙—继续流 2024-12-03 20:03:45

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

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

In case you can't or won't use 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;
}

Note: it assumes that the written length is limited.

Update: with gcc it's possible to do this in a type-safe way, you need the following declaration.

class Log {
    void writeSuccess(const char* const fmt, ...) __attribute__ ((format (printf, 2, 3)));
    //...
};

Info here. Note: it's a warning, not a compile error. If you ignore warnings that's your problem..:)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文