Reputation: 1308
I am trying to finalize my logging class. I have written it from scratch and do not wish to use an alternative library of any kind. My problem lies within the fact that my logger has trouble outputting std::string
s and only works when I denote it with the string.c_str()
function.
Here is my logfile output function:
void Log::writeSuccess(char * text,...)
{
// Grab the variables and insert them
va_list ap;
va_start(ap, text);
char buff[BUFFER_SIZE];
vsnprintf(buff, sizeof(buff), text, ap);
// Output to the log
logfile << "<-!-> " << buff << endl;
}
Here is a sample call to my log class object (ignore the uselessness of the call):
string test("This is a test string!");
errorLog.writeSuccess("Output: %s", test);
I end up with random characters and garbled output.
However, when I append the string, test
with .c_str()
, it outputs the text correctly.
The whole reason I am trying to avoid cstrings is because I understand they are not cross platform and am developing my client to support all the major operating systems.
To summarize:
What is wrong with my log output function? Do you see any way it could be improved?
Should I generally avoid c_strings?
Upvotes: 1
Views: 368
Reputation: 16779
When calling function with variable parameters you must use simple types. For string
you must use c_str()
. There's no workaround. MFC's CString
is designed so that you can get away with using it directly, but that was Microsoft's decision, and part of their design.
EDIT: As I said when calling function with variable parameters you must use string::c_str(). However, instead of C-like functions with variable parameters you can use something like boost::format()
and it's parameter feeding operator %. This also gives you more control over ordering of parameters, which is very handy for i18n.
Upvotes: 1
Reputation: 18522
You're getting random garble when passing an std::string
to vsnprintf
because the format specifier "%s"
is that of a C-string - a char*
.
std::string
is not of type char*
, but std::string.c_str()
is of type char*
. vsnprintf
will basically read char
s pointed to by the address that it presumes is that of a start of a C-string, up until the NUL character '\0'
.
An std::string
pushed onto the stack and passed as an argument to vsnprintf
is not a pointer to a char
, however vsnprintf
will just treat these bytes as an address and start reading char
s/bytes from this address, causing undefined behaviour.
The printf
family of functions are not typesafe, since they rely on a format string and variable argument list, which is why your code will compile but you'll get unexpected results.
Bottom line is the printf
family of functions expect a char*
when you use the format specifier "%s"
.
I also think you're confusing C style strings (char[]
) with the Microsoft-specific CString
class. C style strings won't cause you problems on different platforms at all; the literal "This is a test string!"
is a C style string (const char[]
).
Upvotes: 2