我正在维护一个自定义日志系统,该系统使用宏来执行诸如为每条消息附加时间戳和源文件名之类的事情。如下所示:
AI_LOG("Hello %s", "World!");
可能导致:
(16.38) HelloWorld.cpp LOG: Hello World!
目前,它在堆栈上创建一个char *缓冲区,将输出的初始部分放在缓冲区的开头,然后使用snprintf将输出复制到缓冲区的其余部分。这一切都有效...除了它在堆栈上创建缓冲区,如果我有足够深的堆栈和足够的日志语句并且我不保持缓冲区非常小(例如256个字符),我可以得到堆栈溢出。我现在需要输出更长的字符串,因此将所有这些缓冲区放在堆栈上对我来说不再适用。
考虑到这个背景......我想转移到一个单一的全局字符数组,我会做得很大(可能像4K字符一样开始)。但是,我的理解是,如果我只是说:
#define AI_OUTPUT_BUFFER_SIZE 4092
char AI_OUTPUT_BUFFER[AI_OUTPUT_BUFFER_SIZE];
在我的输出系统的.h文件中,然后我冒着每个包含该.h文件的文件创建单独缓冲区的风险。这是一个真正的问题吗?如果是这样,是否有一个好的(编译器不可知,C ++ 98兼容,非Boost使用)方式来获得我想要的单个缓冲区?
我倾向于在标题中这样做:
#define AI_OUTPUT_BUFFER_SIZE 4096
class AIOutputBuffer
{
public:
static char buffer[AI_OUTPUT_BUFFER_SIZE];
};
然后在.cpp中我可以:
char GAIA::AIOutputBuffer::buffer[AI_OUTPUT_BUFFER_SIZE];
但这让我感到头疼......也许我还没有做好呢?
在人们提出之前......是的,我可能会重写它以使用字符串或流...但我真的不想重写整个系统,也没有时间和资源来做。这个系统运行良好,给了我很大的灵活性 - 我只需要处理内存使用问题。
答案 0 :(得分:0)
从评论中(感谢Dmitri!)我使用extern,它就像一个魅力。所以在标题中:
#define AI_OUTPUT_BUFFER_SIZE 256
extern char AI_OUTPUT_BUFFER[AI_OUTPUT_BUFFER_SIZE];
然后在.cpp:
char AI_OUTPUT_BUFFER[AI_OUTPUT_BUFFER_SIZE];
答案 1 :(得分:0)
当您解决了问题时,有一个更好的解决方案依赖std::string
进行内存管理。此外,它在多线程环境中运行良好。
我们的想法是使用oldschool snprintf
,但让std::string
负责内存管理:
#include <string>
#include <cstdarg>
std::string va(const char* fmt, ...)
{
// make sure your stack can handle a one-time allocation of a buffer of this size
const auto BUFFER_SIZE = 8192;
// ...unless you know you're not going to call this from multiple threads;
// then you can make this buffer static and the size can be increased
char buffer[BUFFER_SIZE];
va_list args;
va_start(args, fmt);
std::vsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);
buffer[sizeof(buffer) - 1] = '\0';
return buffer;
}
用法:此处没有异常:auto logMsg = va("Hello %s", "World!");
。