__int64 CString 返回错误的值 - C++ MFC

__int64 to CString returns wrong values - C++ MFC

本文关键字:C++ MFC 错误 int64 CString 返回      更新时间:2023-10-16

我想将__int64变量转换为CString。代码正是这个

__int64 i64TotalGB;
CString totalSpace;
i64TotalGB = 150;
printf("disk space: %I64d GBn", 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));

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

试试这个:

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

话虽如此,由于MS在字符编码方面的混乱(ha(,在这里使用_T并不是正确的事情,因为CString是由TCHAR而不是_TCHAR组成的。因此,考虑到这一点,不妨使用TEXT()而不是T(),因为它取决于UNICODE而不是_UNICODE

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

此外,此行是错误的,因为它尝试将 ATLCString作为char*传递(也称为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());

请注意,在我的配置下%lstotalSpace.GetString()返回了一个const wchar_t*。但是,由于">printf当前不支持输出到 UNICODE 流中">,因此此行的正确版本(将支持当前代码页之外的字符(是按以下方式调用wprintf()

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

说了这么多,这里有一个一般性的建议,不管问题背后的直接问题是什么。如今更好的做法略有不同,我引用了@IInspectable的可敬回答,说"泛型文本映射在 20 年前是相关的"。

还有什么选择?如果没有足够充分的理由,请尝试显式坚持使用CStringW(支持 CRT 的 Unicode 字符类型字符串(。首选L字符文本,而不是古老的数据/文本映射,后者取决于程序中是否定义了常量_UNICODE_MBCS。相反,更好的做法是使用所有 API 和语言库调用的宽字符版本,例如wprintf()而不是printf()

该错误是代码中许多问题的结果,特别是以下两个问题:

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

    这会以不打算使用的方式使用_T宏。它应该包装单个字符串文本。在代码中,它包装了第二个参数。

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

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

建议的做法是完全删除泛型文本映射,转而在整个1中使用 Unicode(即 Windows 上的 UTF-16LE(。泛型文本映射在 20 年前是相关的,以便于将 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 GBn", 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来明确说明它。

试试这个

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