Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

__int64 to CString returns wrong values - C++ MFC

I want to convert a __int64 variable into a CString. The code is exactly this

__int64 i64TotalGB;
CString totalSpace;
i64TotalGB = 150;
printf("disk space: %I64d GB\n", i64TotalGB);
totalSpace.Format(_T("%I64d", i64TotalGB));
printf("totalSpace contains: %s", totalSpace);

the first printf prints

"disk space: 150GB"

which it's correct, but the second printf prints randomly high numbers like

"totalSpace contains: 298070026817519929"

I also tried to use a INT64 variable instead of a __int64 variable, but the result is the same. What can be the cause of this?

like image 200
Luca Corsini Avatar asked Sep 25 '18 09:09

Luca Corsini


1 Answers

Here:

totalSpace.Format(_T("%I64d", i64TotalGB));

you're passing i64TotalGB as an argument to the _T() macro instead of passing it as the second argument to Format().

Try this:

totalSpace.Format(_T("%I64d"), i64TotalGB);

Having said that, thanks to MS's mess (ha) around character encodings, using _T here is not the right thing, as CString is composed of a TCHAR and not _TCHAR. So taking that into account, might as well use TEXT() instead of T(), as it is dependent on UNICODE and not _UNICODE:

totalSpace.Format(TEXT("%I64d"), i64TotalGB);

In addition, this line is wrong as it tries to pass an ATL CString as a char* (a.k.a. C-style string):

printf("totalSpace contains: %s", totalSpace);

For which the compiler gives this warning:

warning C4477: 'printf' : format string '%s' requires an argument of type 'char *', but variadic argument 1 has type 'ATL::CString'

While the structure of CString is practically compatible with passing it like you have, this is still formally undefined behavior. Use CString::GetString() to safeguard against it:

printf("totalSpace contains: %ls", totalSpace.GetString());

Note the %ls as under my configuration totalSpace.GetString() returned a const wchar_t*. However, as "printf does not currently support output into a UNICODE stream.", the correct version for this line, that will support characters outside your current code page, is a call to wprintf() in the following manner:

wprintf("totalSpace contains: %s", totalSpace.GetString());

Having said ALL that, here's a general advice, regardless of the direct problem behind the question. The far better practice nowadays is slightly different altogether, and I quote from the respectable answer by @IInspectable, saying that "generic-text mappings were relevant 2 decades ago".

What's the alternative? In the absence of good enough reason, try sticking explicitly to CStringW (A Unicode character type string with CRT support). Prefer the L character literal over the archaic data/text mappings that depend on whether the constant _UNICODE or _MBCS has been defined in your program. Conversely, the better practice would be using the wide-character versions of all API and language library calls, such as wprintf() instead of printf().

like image 88
Geezer Avatar answered Sep 26 '22 01:09

Geezer