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

Общий совет: перестаньте притворяться, что вы нацеливались на Win9x. Ты не такой. Используйте CStringW вместо CString, замените _T и аналогичные макросы префиксом L и живите счастливой жизнью с тех пор. Другими словами: CStringW totalSpace; totalSpace.Format(L"%I64d", i64TotalGB); wprintf(L"totalSpace contains: %s", totalSpace.GetString());.

IInspectable 25.09.2018 11:40
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
7
1
504
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

попробуй это

totalSpace.Format(_T("%I64d"), i64TotalGB);
Ответ принят как подходящий

Здесь:

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, в котором говорится, что "отображение общего текста было актуально два десятилетия назад".

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

@IInspectable Теперь я вижу это в документах:«printf в настоящее время не поддерживает вывод в поток UNICODE». - внес правку, чтобы отразить. довольно деталь, но достаточно важная, чтобы отметить ИМХО

Geezer 25.09.2018 17:14

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

  • 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++ для расширенных символов.

Фиксированный код выглядит так:

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

Другие вопросы по теме