Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How sprintf works with CString and std::string

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?

like image 766
rmi Avatar asked Feb 26 '14 09:02

rmi


People also ask

Can I use string for sprintf?

The sprintf() function in C++ is used to write a formatted string to character string buffer.

What is the difference between string and CString in C++?

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.

How do you convert STD string to CString?

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.

What is the equivalent of sprintf in C++?

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.


1 Answers

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;
}
like image 117
marcinj Avatar answered Sep 18 '22 22:09

marcinj