__int64 в CString возвращает неправильные значения - C ++ MFC - PullRequest
0 голосов
/ 25 сентября 2018

Я хочу преобразовать переменную __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, но результат тот же.Что может быть причиной этого?

Ответы [ 3 ]

0 голосов
/ 25 сентября 2018

Здесь:

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

вы передаете i64TotalGB в качестве аргумента макросу _T() вместо того, чтобы передать его в качестве второго аргумента Format().

Попробуйте это:

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

Сказав, что благодаря беспорядку (ха) MS вокруг кодировки символов, использование _T здесь не является правильным, так как CString состоит изTCHAR, а не _TCHAR.Таким образом, принимая это во внимание, можно также использовать TEXT() вместо T(), поскольку оно зависит от UNICODE, а не _UNICODE:

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

Кроме того, эта строка неверна какон пытается передать ATL CString как 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());

Обратите внимание на %ls, как в моей конфигурации totalSpace.GetString() вернул const wchar_t*.Однако, поскольку "printf в настоящее время не поддерживает вывод в поток UNICODE. " , правильная версия для этой строки, которая будет поддерживать символы вне вашей текущей кодовой страницы , это вызов wprintf() следующим образом:

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

Сказав ВСЁ, вот общий совет, независимо от прямой проблемы, стоящей за вопросом.Гораздо лучшая практика в наше время немного отличается, и я цитирую респектабельный ответ @IInspectable, в котором говорится, что «отображения общего текста были актуальны 2 десятилетия назад» .

Какая альтернатива?При отсутствии достаточных причин попробуйте явно придерживаться CStringW ( Строка символьного типа Unicode с поддержкой CRT ).Предпочитайте L символьный литерал над архаичным отображением данных / текста , чтобы зависело от того, была ли константа _UNICODE или _MBCSопределено в вашей программе .И наоборот, лучшей практикой будет использование широкосимвольных версий всех вызовов API и языковых библиотек, таких как wprintf() вместо printf().

0 голосов
/ 25 сентября 2018

Ошибка является результатом многочисленных проблем с кодом, а именно этих 2:

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

    При этом используется макрос _T таким образом, он не предназначен для использования.Следует обернуть один символьный строковый литерал.В коде он содержит второй аргумент.

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

    Предполагается, что строка символов в кодировке ANSI, но передает объект CString, который может хранитькак строки ANSI, так и строки в кодировке Unicode.

Рекомендуемый порядок действий - вообще отказаться от отображений общего текста в пользу использования Unicode (это UTF-16LE в Windows) на протяжении 1 .Общие сопоставления текста были актуальны два десятилетия назад, чтобы упростить перенос кода Win9x на продукты на базе Windows NT.

Для этого

  • Выберите CStringW вместо CString.
  • Удалите все вхождения _T, TEXT и _TEXT и замените их префиксом L.
  • Используйте широко-символьную версию Windows API, CRT и C ++ Standard Library.

Фиксированный код выглядит следующим образом:

__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.

0 голосов
/ 25 сентября 2018

попробуйте

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