This works because the first element of the CString class is a pointer to a char array. In fact, the only field in a CString is a pointer to a string array. This class uses some tricks to hide internal data (e.g. string length, reserved buffer size, etc.) by highlighting one large buffer and then leaving the only class pointer pointed to by the char array to get to these internal fields data, it shifts this pointer at a known offset.
What you need to do is call s.GetBuffer (0); or (LPCTSTR); but using it like
sprintf(z2, "%s", ss);
was resolved as designed by the creators of MFC, but of course it works under Windows on other platforms that it might crash.
[edit after comments]
your code will be more secure 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 these static_cast-s, especially if your sprintf-s have a lot of options. This, as far as I remember (and, in my opinion) in design, C ++ style casts are intended for you to rethink your design so as not to use translations at all. In your case, instead of using sprintf, you should use std :: wstringstream (assuming you use the UNICODE assembly):
#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; }
source share