2013-10-08 11 views
0

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

Почему нет двух разных способов создания эквивалента 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(); 
}; 
+1

'// Почему не эта работа' - У вас есть указатель во временный буфер. – chris

ответ

2

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

Update: 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

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

+0

Спасибо за объяснение. Я не понимал, что возвращаемый std :: wstring выходит за рамки. (PS Я исправил ту часть, которую вы сказали, которая не должна компилироваться. Это была опечатка). – sgryzko

+0

Я понимаю, что 'std :: string' использует' char'? Будучи программистом старого времени, пытающимся научиться новому способу делать вещи, у меня достаточно проблем с поиском оправдания для изучения 'std: string'. Не говорите мне, что не поддерживает широкие символы из коробки. –

1

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

+0

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

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

Правильно ли предположить, что без каких-либо специальных символов мой простой присваивающий будет работать так, как ожидалось? – sgryzko