I have to format std::string with sprintf and send it into file stream. How can I do this?
Took the idea from Dacav and pixelpoint's answer. I played around a bit and got this:
#include
#include
#include
std::string format(const char* fmt, ...)
{
va_list vl;
va_start(vl, fmt);
int size = vsnprintf(0, 0, fmt, vl) + sizeof('\0');
va_end(vl);
char buffer[size];
va_start(vl, fmt);
size = vsnprintf(buffer, size, fmt, vl);
va_end(vl);
return std::string(buffer, size);
}
With sane programming practice I believe the code should be enough, however I'm still open to more secure alternatives that are still simple enough and would not require C++11.
And here's another version that makes use of an initial buffer to prevent second call to vsnprintf()
when initial buffer is already enough.
std::string format(const char* fmt, ...)
{
va_list vl;
int size;
enum { INITIAL_BUFFER_SIZE = 512 };
{
char buffer[INITIAL_BUFFER_SIZE];
va_start(vl, fmt);
size = vsnprintf(buffer, INITIAL_BUFFER_SIZE, fmt, vl);
va_end(vl);
if (size < INITIAL_BUFFER_SIZE)
return std::string(buffer, size);
}
size += sizeof('\0');
char buffer[size];
va_start(vl, fmt);
size = vsnprintf(buffer, size, fmt, vl);
va_end(vl);
return std::string(buffer, size);
}
(It turns out that this version is just similar to Piti Ongmongkolkul's answer, only that it doesn't use new
and delete[]
, and also specifies a size when creating std::string
.
The idea here of not using new
and delete[]
is to imply usage of the stack over the heap since it doesn't need to call allocation and deallocation functions, however if not properly used, it could be dangerous to buffer overflows in some (perhaps old, or perhaps just vulnerable) systems. If this is a concern, I highly suggest using new
and delete[]
instead. Note that the only concern here is about the allocations as vsnprintf()
is already called with limits, so specifying a limit based on the size allocated on the second buffer would also prevent those.)