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

Luc*_*ini 7 c++ printf mfc c-strings int64

我想将__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);
Run Code Online (Sandbox Code Playgroud)

第一个printf打印

"disk space: 150GB"
Run Code Online (Sandbox Code Playgroud)

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

"totalSpace contains: 298070026817519929"

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

Rei*_*ica 10

这里:

totalSpace.Format(_T("%I64d", i64TotalGB));
Run Code Online (Sandbox Code Playgroud)

i64TotalGB作为一个参数传递给_T()而不是作为第二个参数传递给它Format().

试试这个:

totalSpace.Format(_T("%I64d"), i64TotalGB);
Run Code Online (Sandbox Code Playgroud)

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

totalSpace.Format(TEXT("%I64d"), i64TotalGB);
Run Code Online (Sandbox Code Playgroud)

另外,这行是错误的,因为它试图将ATL CString作为char*(又名C风格的字符串)传递:

printf("totalSpace contains: %s", totalSpace);
Run Code Online (Sandbox Code Playgroud)

编译器为此提供此警告:

warning C4477: 'printf' : format string '%s' requires an argument of type 'char *', but variadic argument 1 has type 'ATL::CString'
Run Code Online (Sandbox Code Playgroud)

虽然结构CString实际上与你传递的方式兼容,但这仍然是正式未定义的行为.用于CString::GetString()防范它:

printf("totalSpace contains: %ls", totalSpace.GetString());
Run Code Online (Sandbox Code Playgroud)

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

wprintf("totalSpace contains: %s", totalSpace.GetString());
Run Code Online (Sandbox Code Playgroud)

说完这一切,这是一般性的建议,不管问题背后的直接问题.现在更好的做法完全略有不同,我引用@IInspectable的可敬答案,说"通用文本映射在20年前是相关的".

有什么选择?如果没有足够的理由,请尝试明确地坚持CStringW(具有CRT支持的Unicode字符类型字符串).喜欢L 字符文字在陈旧的数据/文本映射的是取决于是否恒定_UNICODE_MBCS已经在你的程序中定义.相反,更好的做法是使用所有API和语言库调用的宽字符版本,例如wprintf()代替printf().


IIn*_*ble 6

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

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

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

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

    这假设是ANSI编码的字符串,但传递一个CString对象,该对象可以存储ANSI和Unicode编码的字符串.

建议的做法是完全删除通用文本映射,支持在整个1中使用Unicode(Windows上为UTF-16LE).二十年前,通用文本映射是相关的,以便于将Win9x代码移植到基于Windows NT的产品.

去做这个

  • 选择CStringW结束CString.
  • 删除,,和的所有出现_T,TEXT_TEXTL前缀替换它们.
  • 使用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
Run Code Online (Sandbox Code Playgroud)

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


1 除非有正当理由来使用使用的字符编码char作为其底层类型(如UTF-8或ANSI).在这种情况下,你应该通过使用来明确它CStringA.