Reputation: 50831
Does anybody know why this codes is not correct according to this site:
CString First( "John" );
CString Last( "Doe" );
CString Name;
Name.Format( "%s %s", First, Last ); // Name may be garbage text
Name.Format( "%s %s", (LPCSTR)First, (LPCSTR)Last ); // this is the correct way
The Microsoft documentation of CString::Format says:
...When you pass a character string as an optional argument, you must cast it explicitly as LPCTSTR...
I always use the "wrong" way (without the LPCSTR cast) and I never had problems.
Am I missing something here ?
Upvotes: 3
Views: 4480
Reputation: 11
Because it would break if you used sub-classed CString arguments.
Upvotes: 1
Reputation: 60034
I think (sorry, I don't have MFC available now to check) that the cast is needed just for efficiency reason, to avoid an useless temporary copy that MFC must do when the argument type if unknown (CString is lazily copied on modify).
The trick it's that CString memory allocation reserve space before this
for some essential data other than the buffer (TCHAR*), like the reference counter.
Then when you pass a CString by value to a variadic function, it 'sees' the buffer (a pointer) The cast 'extract' just the buffer, without invoking the copy constructor.
Upvotes: 1
Reputation: 36092
Because there is no cast done inside of the Format function just as there is no cast done when you specify an argument to printf()
If you write printf( "%d", a );
no cast is done to a
since printf assumes that %d
already tells what data type a
is.
In order to make sure that CString
is converted to a LPCSTR
i.e. %s
you need to cast the argument which will call the operator on the CString
that returns the LPCSTR
. In later versions of CString the string is stored so that when you write without the cast it will still be printed as a LPCSTR but to be sure it is better to do a cast.
Or put in another way: When a variadic function goes through the arguments it uses the format specifier to know the sizes of the arguments, if the format specifier does not match the arguments you get garbage. Since there is no format specifier for CString you need to convert CString to a LPCSTR.
BTW you should use static_cast<LPCSTR>(First), static_cast<LPCSTR>(Last)
in C++
Upvotes: 3
Reputation: 42598
Casting to LPCSTR invokes the cast operator operator LPCSTR()
(which should be operator const char *()
.
Not calling LPCSTR means you are passing the entire CString object then blindly using the first 32 or 64 bits of the underlying structure as a char pointer.
To recap: LPCSTR(str)
is calling a method to ensure proper behavior, while str
is blind bit twiddling.
Upvotes: 2