CString s = "test";
std::string ss = "test";
char z[100];
sprintf(z, "%s", ss.c_str()); // z = "test" : OK
char z2[100];
sprintf(z2, "%s", ss); // z2 = "(null)" : OK. undefined behavior is expected
char z3[100];
sprintf(z3, "%s", s); // z3 = "test" : How is this possible ?!
Can anybody explain how CString
works properly with sprintf
?
The sprintf() function in C++ is used to write a formatted string to character string buffer.
What's different with <string>, <cstring> in C++? The cstring header provides functions for dealing with C-style strings — null-terminated arrays of characters. This includes functions like strlen and strcpy. It's the C++ version of the classic string.
Converting a std::string to a CString is as simple as: std::string stdstr("foo"); CString cstr(stdstr. c_str()); This works for both UNICODE and MBCS projects.
The sprint() function is present inside the C and C++ also. This function is used to store something inside a string. The syntax is like the printf() function, the only difference is, we have to specify the string into it. In C++ also, we can do the same by using ostringstream.
It works because the first element of CString class is a pointer to char array. Actually, the only field in CString is a pointer to a string array. This class uses some tricks to hide internal data (like string length, reserved buffer size, etc) by allocating one big buffer and then leaving the only class pointer pointed to char array, to get to those internal data fields it shifts this pointer by known offset.
What you should do is call s.GetBuffer(0); or (LPCTSTR)s; but using it as
sprintf(z2, "%s", ss);
was allowd as by design of MFC creators, of course it works under Windows on other platforms it might crash.
[edit after comments]
your code will be safer if instead of c-style casts like (LPCTSTR)s
you will use c++ cast: static_cast<LPCTSTR>(s);
. But very soon you will find out that your code gets ugly with all this static_cast-s, especially if your sprintf-s have lots of parameters. This is as far as I remember (and in my opinion) by design, c++ style casts are designed to make you rethink your design to not use casts at all. In your case instead of using sprintf you should use std::wstringstream (assuming you use UNICODE build):
#include<sstream>
std::wostream & operator<< (std::wostream &out, CString const &s) {
out << s.GetString();
return out;
}
int main(){
CString s = _T("test");
std::wstringstream ss;
ss << s; // no cast required, no UB here
std::wcout << ss.str();
return 0;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With