C++Snippets
Jump to navigation
Jump to search
String formatting without buffer overrun
This is a complete small program that shows how to allocate a string buffer with the correct size so that a C string formatting routine like sprintf can be used without the fear of a buffer overrun.
The example is mainly useful in a C environment - in C++ you should use stringstream instead of string formatting.
#include <sstream> // for std::stringstream
#include <cstdarg> // for variable arguments stuff
#include <cstddef> // for nullptr
#include <iostream> // for std::cout
// ----------------------------------------------------------------------
std::stringstream messageStream("");
// ----------------------------------------------------------------------
// Caller must pass a va_list parameter that has been initialized with
// va_start(), and caller must clean up the va_list parameter with va_end().
// This function modifies the va_list parameter.
void WriteFormattedStringToStringStreamArglist(const char* formatString, va_list arglist)
{
// Perform a "probing" call to vsnprintf(). We do this so that the function
// tells us how long the resulting string would have been, so that we can
// allocate a buffer of the correct length. For this we need a copy of
// arglist, the copy must be made while the original arglist is still in
// its initialized state.
va_list arglistCopy;
va_copy(arglistCopy, arglist);
int lengthOfFormattedStringWithoutNullTerminator = vsnprintf(nullptr, 0, formatString, arglistCopy);
va_end(arglistCopy);
if (lengthOfFormattedStringWithoutNullTerminator >= 0)
{
size_t bufferSize = lengthOfFormattedStringWithoutNullTerminator + 1;
char formattedStringBuffer[bufferSize];
// No need to call va_start/va-end - that's the responsibility of the caller
vsnprintf(formattedStringBuffer, bufferSize, formatString, arglist);
messageStream << formattedStringBuffer;
}
else
{
messageStream
<< "WriteFormattedStringToStringStreamArglist error: vsnprintf encountered encoding error, return value was "
<< lengthOfFormattedStringWithoutNullTerminator;
}
}
// ----------------------------------------------------------------------
void WriteFormattedStringToStringStream(const char* formatString, ...)
{
va_list arglist;
va_start(arglist, formatString);
WriteFormattedStringToStringStreamArglist(formatString, arglist);
va_end(arglist);
}
// ----------------------------------------------------------------------
int main(int argc, char** argv)
{
const char* formatString = "Hello %s";
const char* valueString = "world";
WriteFormattedStringToStringStream(formatString, valueString);
std::cout << messageStream.str() << std::endl;
}