Stop using format functions in C++
TL;DR: They are unsafe, vulnerable to all sorts of buffer overrun exploits and a pain to debug when you make a mistake.
std::cout
and the standard C++ streams are much more robust than printf
and the C IO library and formatting functions. Format strings tend to be more readable and there is some value in separating the data from the presentation, but unfortunately, they are a C mechanism that is incompatible with C++'s object model. So you cannot, for instance, pass a C++ class type to one of those functions (don't even think about passing it a std::string!
).
Format strings are also not type safe, since you wave compile-time type inference and rely on manually matching the type of each parameter with the %
s in the format string. In the end, that's a recipe for disaster and these issues outweigh any gains in readability. Having to manually specify the type in the format, when the compiler always knows the type of the variable passed in, is also a violation of the DRY principle.
Better options exist, beside the C++ streams, if you really don't dig the <<
operator syntax:
That said, let's look at your code. What could be wrong?
It could be a buffer overflow in Gui::message()
. The buffer is sized to 256 characters, if the string is longer than that, you run into trouble.
What you can do is increase the buffer size and test. Also, make sure to manually terminate the string, just in case:
char buffer[1024];
va_list argptr;
va_start(argptr, text);
vsnprintf(buffer, sizeof(buffer), text, argptr);
va_end(argptr);
buffer[sizeof(buffer) - 1] = '\0';
This code also seems suspicious:
void Gui::render()
{
for(auto iter = log.begin(); iter != log.end(); iter++)
{
terminal_printf(1, 45, (*iter));
}
}
There's not enough information here to be certain, but what are the contents of log
? chars, strings?
If (*iter)
is returning a char
, then the correct way to print it with a format is:
terminal_printf(1, 45, "%c", (*iter));
If it contains a char *
string (array of chars), the correct print call is:
terminal_printf(1, 45, "%s", (*iter));
Assuming the signature of terminal_printf
is something like:
void terminal_printf(int, int, const char*, ...);