简体   繁体   中英

How to create a single global char* in C++

I am maintaining a custom logging system that uses macros to do things like append a timestamp and source file name to each message. So something like:

AI_LOG("Hello %s", "World!");

might result in:

(16.38) HelloWorld.cpp LOG: Hello World!

Currently, it creates a char* buffer on the stack, places the initial part of the output into the beginning of the buffer, and then uses snprintf to copy the output into the remainder of the buffer. This all works... except that it creates the buffer on the stack, and if I have a deep enough stack with enough log statements and I don't keep the buffer quite small (eg 256 characters), I can get stack overflows. I now have a need to output much longer strings, so putting all those buffers on the stack isn't going to work for me anymore.

With that background in mind... I'd like to move to a single global char array, which I will make quite big (probably something like 4K characters to start). However, my understanding is that if I just say something like:

#define AI_OUTPUT_BUFFER_SIZE 4092
char AI_OUTPUT_BUFFER[AI_OUTPUT_BUFFER_SIZE];

in my output system's .h file, then I run the risk of having a separate buffer being created by every file that includes that .h file. Is that a real problem? If so, is there a good (compiler-agnostic, C++98 compliant, non-Boost-using) way to get the single buffer that I want?

I was leaning toward doing this in the header:

#define AI_OUTPUT_BUFFER_SIZE 4096
class AIOutputBuffer
{
public:
    static char buffer[AI_OUTPUT_BUFFER_SIZE];
};

And then in the .cpp I can:

char GAIA::AIOutputBuffer::buffer[AI_OUTPUT_BUFFER_SIZE];

But that's giving me linker headaches... Maybe I'm not quite doing it right yet?

And before people suggest it... yes, I could probably rewrite it to use strings or streams... but I don't really want to rewrite the whole system, nor do I have the time and resources to do that. This system works well and gives me a lot of flexibility - I just need to handle the memory usage problem.

From the comments (thanks Dmitri!) I used extern, and it worked like a charm. So in the header:

#define AI_OUTPUT_BUFFER_SIZE 256
extern char AI_OUTPUT_BUFFER[AI_OUTPUT_BUFFER_SIZE];

then in the .cpp:

char AI_OUTPUT_BUFFER[AI_OUTPUT_BUFFER_SIZE];

While you solved your problem, there's a nicer solution that relies on std::string for memory management. Also, it works perfectly well in a multithreaded environment.

The idea is to use the oldschool snprintf but let std::string take care of memory management:

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

Usage: nothing unusual here: auto logMsg = va("Hello %s", "World!"); .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM