Неожиданные результаты с преобразованием строк wchar_t и c_str

0

Основываясь на этом ответе на связанный вопрос, я попытался написать метод, который преобразует стандартную строку в широкую строку, которую затем я могу преобразовать в wchar_t *.

Почему не два разных способа создания эквивалента wchar_t *? (Я показал значения, которые дает мой отладчик).

TEST_METHOD(TestingAssertsWithGetWideString)
{
   std::wstring wString1 = GetWideString("me");
   const wchar_t* wchar1 = wString1.c_str(); // wchar1 = "me"
   const wchar_t* wchar2 = GetWideString("me").c_str(); // wchar2 = "ﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮ@" (Why?!)
}

где GetWideString определяется следующим образом:

inline const std::wstring GetWideString(const std::string &str)
{
   std::wstring wstr;
   wstr.assign(str.begin(), str.end());

   return wstr;
};

Примечание: следующее не работает.

const wchar_t* wchar2 = GetWChar("me");

const wchar_t *GetWChar(const std::string &str)
{
   std::wstring wstr;
   wstr.assign(str.begin(), str.end());

   return wstr.c_str();
};
Теги:
string
type-conversion
wstring
string-conversion

3 ответа

2
Лучший ответ

Каждый раз, когда вы вызываете GetWideString(), вы создаете новый std::wstring, у которого есть новый выделенный буфер памяти. Вы сравниваете указатели на разные блоки памяти (при условии, что Assert::AreEqual() просто сравнивает сами указатели, а не содержимое блоков памяти, на которые указывают).

Обновление: const wchar_t* wchar2 = GetWideString("me").c_str(); не работает, потому что GetWideString() возвращает временную std::wstring которая выходит из области действия и освобождается, как только инструкция завершена. Таким образом, вы получаете указатель на временный блок памяти, а затем оставляете этот указатель висящим, когда эта память освобождается, прежде чем вы сможете использовать указатель для чего-либо.

Кроме того, const wchar_t* wchar2 = GetWChar("me"); не следует компилировать. GetWChar() возвращает std::wstring, который не реализует неявное преобразование в wchar_t*. Вы должны использовать метод c_str() чтобы получить wchar_t* из std::wstring.

  • 0
    Хороший вопрос, но я отредактировал свой вопрос, чтобы уточнить, что я ищу.
  • 0
    Спасибо за объяснение. Я не осознавал, что возвращаемое std :: wstring выходит из области видимости. (PS Я исправил ту часть, которая, как вы сказали, не должна компилироваться. Это была опечатка).
Показать ещё 2 комментария
1

Потому что два указателя не равны. wchar_t * не является String, поэтому вы получаете общий атрибут AreEqual.

  • 0
    Хороший вопрос, но я отредактировал свой вопрос, чтобы уточнить, что я ищу.
0

std::wstring содержит широкие символы типа wchar_t. std::string содержит символы типа char. Для специальных символов, хранящихся в std::string используется многобайтовая кодировка, то есть некоторые символы представлены двумя символами внутри такой строки. Таким образом, преобразование между ними не может быть простым вызовом простого assign.

Чтобы преобразовать между "широкими" строками и многобайтными строками, вы можете использовать следующие помощники (только для Windows):

// multi byte to wide char:
std::wstring s2ws(const std::string& str)
{
    int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
    std::wstring wstrTo(size_needed, 0);
    MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
    return wstrTo;
}

// wide char to multi byte:
std::string ws2s(const std::wstring& wstr)
{
    int size_needed = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), int(wstr.length() + 1), 0, 0, 0, 0); 
    std::string strTo(size_needed, 0);
    WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), int(wstr.length() + 1), &strTo[0], size_needed, 0, 0); 
    return strTo;
}
  • 0
    Правильно ли предположить, что без каких-либо специальных символов мое простое назначение будет работать так, как ожидается?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню