__int64 到 CString returns 错误值 - C++ MFC

__int64 to CString returns wrong values - C++ MFC

我想将 __int64 变量转换为 CString。代码就是这样

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

第一个 printf 打印

"disk space: 150GB"

这是正确的,但第二个 printf 打印随机高数字,如

"totalSpace contains: 298070026817519929"

我也尝试过使用 INT64 变量而不是 __int64 变量,但结果是一样的。这可能是什么原因造成的?

试试这个

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

这里:

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

您将 i64TotalGB 作为参数传递给 _T() macro,而不是将其作为第二个参数传递给 Format()

试试这个:

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

话虽如此,由于 MS 在字符编码方面的混乱 (ha),在这里使用 _T 是不正确的,因为 CStringTCHAR 组成,而不是_TCHAR。所以考虑到这一点,不妨使用 TEXT() 而不是 T(),因为它依赖于 UNICODE 而不是 _UNICODE:

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

此外,这一行是错误的,因为它试图将 ATL CString 作为 char*(a.k.a。C 风格的字符串):

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

编译器为此发出警告:

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

虽然 CString 的结构实际上可以像您一样传递它,但这在形式上仍然是 未定义的行为 。使用CString::GetString()来防范它:

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

请注意 %ls,因为在我的配置下 totalSpace.GetString() 返回了 const wchar_t*。但是,作为 "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,是以下列方式调用 wprintf()

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

说了这么多,这里有一个一般性的建议,不管问题背后的直接问题是什么。现在更好的做法完全略有不同,我引用@IInspectable 令人尊敬的回答,说 "generic-text mappings were relevant 2 decades ago".

还有什么选择?在没有足够充分理由的情况下,请尝试明确坚持 CStringWA 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() 而不是 printf().

该错误是代码的众多问题的结果,特别是这些 2:

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

    这以一种不应该使用的方式使用了 _T macro。它应该包装单个字符串文字。在代码中它包含了第二个参数。

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

    这假定一个 ANSI 编码的字符串,但传递一个 CString 对象,它可以存储 ANSI 和 Unicode 编码的字符串。

建议的做法是完全放弃 generic-text mappings,转而在整个 1 中使用 Unicode(即 Windows 上的 UTF-16LE)。通用文本映射在 2 年前就已存在,用于简化将 Win9x 代码移植到 Windows 基于 NT 的产品。

这样做

  • 选择 CStringW 而不是 CString
  • 删除所有出现的 _TTEXT_TEXT,并用 L 前缀替换它们。
  • 使用 Windows API、CRT 和 C++ 标准库的宽字符版本。

固定代码如下所示:

__int64 i64TotalGB;
CStringW totalSpace;  // Use wide-character string
i64TotalGB = 150;
printf("disk space: %I64d GB\n", i64TotalGB);
totalSpace.Format(L"%I64d", i64TotalGB);  // Use wide-character string literal
wprintf(L"totalSpace contains: %s", totalSpace.GetString());  // Use wide-character library

在一个不相关的说明中,虽然在可变参数列表中传递 CString 对象代替字符指针在技术上是安全的,但这是一个实现细节,并没有正式记录工作。如果您关心正确的代码,请致电 CString::GetString()


1 除非有正当理由使用使用 char 作为其基础类型的字符编码(如 UTF-8 或 ANSI ).在那种情况下,您仍然应该使用 CStringA.

明确说明