Мне нужно преобразовать CString в double в Embedded Visual C++, который поддерживает только старый стиль C++. Я использую следующий код
CString str = "4.5";
double var = atof( (const char*) (LPCTSTR) str )
и результат var=4.0
, поэтому я теряю десятичные цифры.
Я сделал еще один тест
LPCTSTR str = "4.5";
const char* var = (const char*) str
и снова результат var=4.0
Может ли кто-нибудь помочь мне получить правильный результат?
CString
не является const char*
Чтобы преобразовать CString TCHAR в ASCII, используйте макрос CT2A — это также позволит вам преобразовать строку в UTF8 (или любую другую кодовую страницу Windows):
// Convert using the local code page
CString str(_T("Hello, world!"));
CT2A ascii(str);
TRACE(_T("ASCII: %S\n"), ascii.m_psz);
// Convert to UTF8
CString str(_T("Some Unicode goodness"));
CT2A ascii(str, CP_UTF8);
TRACE(_T("UTF8: %S\n"), ascii.m_psz);
Там макросы являются частью ATL, а не стандартом С++. Прочтите это для получения инструкций по использованию docs.microsoft.com/en-us/previous-versions/87zae4a3(v=vs.140). Скорее всего, вы не включаете заголовки. #include <atldef.h> #include <atlstr.h>
Нет, _wtof нет, только atof
Я не пытался включать atldef.h, так как нашел решение с помощью scanf (см. ответ ниже). Но большое спасибо за помощь.
Последний абзац неверный. Проблема здесь в символе кодирование, а не в конкретных используемых символах. Строка "4.5"
кодируется как 34 2E 35 00
(ASCII) и 34 00 2E 00 35 00 00 00
(UTF-16 LE). Когда вы преобразуете строку Unicode в строку ASCII (или ANSI), вы усекаете ее, в результате чего получается строка 34 00
. Этот последний фрагмент кода работает только тогда, когда ваш проект настроен на использование кодировки MBCS, чего вы никогда не хотите.
Нашел решение с помощью scanf
CString str = "4.5"
double var=0.0;
_stscanf( str, _T("%lf"), &var );
Это дает правильный результат var=4.5
Спасибо всем за комментарии и помощь.
Проблема здесь в том, что вы лжете компилятору, а компилятор доверяет вам. Используя Embedded Visual C++, я предполагаю, что вы ориентируетесь на Windows CE. Windows CE предоставляет только поверхность Unicode API, поэтому ваш проект, скорее всего, настроен на использование Unicode (кодировка UTF-16 LE).
В этом случае CString
заменяется на CStringW
, в котором кодовые единицы хранятся как wchar_t
. Когда вы делаете (const char*) (LPCTSTR) str
, вы переходите от wchar_t const*
к char const*
. Учитывая ввод, первый байт имеет значение 52 (кодировка ASCII для символа 4
). Второй байт имеет значение 0. Это интерпретируется как терминатор строки в стиле C. Другими словами, вы передаете строку "4"
своему вызову atof
. Естественно, в результате вы получите значение 4.0
.
Чтобы исправить код, используйте что-то вроде следующего:
CStringW str = L"4.5";
double var = _wtof( str.GetString() );
_wtof — это специфичное для Microsoft расширение CRT.
Обратите особое внимание на две вещи:
CString
с кодировкой символов явный (CStringW
). Всегда четко указывайте типы строк. Это помогает читать ваш код и выявлять ошибки до того, как они произойдут (хотя все эти приведения в стиле C в исходном коде полностью устраняют это).Также рассмотрите возможность определения макроса _CSTRING_DISABLE_NARROW_WIDE_CONVERSION, чтобы предотвратить непреднамеренное преобразование набора символов (например, CString str = "4.5";
). Это также помогает вам обнаруживать ошибки на ранней стадии (если только вы не справитесь с этим с помощью приведения типов в стиле C).
К сожалению, в Embedded Visual C++ 4.0 нет типа wchar_t, как нет и метода GetString в этой версии MFC для CString. К тому же вы только критикуете, не давая ответа на вопрос. Так что ваш комментарий не актуален.
Используйте WCHAR
, если компилятор не поддерживает wchar_t
. Если ваша версия MFC не предоставляет элемент GetString
, используйте operator LPCWSTR()
.
Вы уверены, что источник (
str
) действительно указывает на строку, которую вы думаете? Если вы пройдёте код в отладчике, что он вам скажет?