Проблема преобразования последовательности двухбайтовых символов в Visual Studio 2015
Я пытаюсь преобразовать двухбайтовую последовательность символов (DBCS) в CP936 в wchar_t
используя язык C++. Это код:
#include <iostream>
#include <locale>
#include <codecvt>
// 国 in CP936
char const src[] = "\xB9\xFA";
int main()
{
std::locale loc(".936");
typedef std::codecvt<wchar_t, char, std::mbstate_t> codecvt_type;
codecvt_type const & cvt = std::use_facet<codecvt_type>(loc);
std::mbstate_t state;
std::memset(&state, 0, sizeof(state));
char const * src_mid = src;
wchar_t buf[10];
wchar_t * buf_mid = buf;
std::codecvt_base::result res = cvt.in(state,
src, src + 2, src_mid,
buf, buf + 10, buf_mid);
int eno = errno;
std::cout << "res: " << +res << "\n"
<< "errno: " << eno << "\n";
return 0;
}
Теперь преобразование всегда заканчивается ошибкой и errno
установить на 42, что EILSEQ
, Я отладил код и думаю, что вижу, что идет не так, но не понимаю, почему.
Что идет не так, так это то, что код, который в конечном итоге приводит к вызову MultiByteToWideChar()
, имеет условное, как это:
if ( ploc->_Isleadbyte[ch >> 3] & (1 << (ch & 7)) )
Эта ветвь никогда не берется, несмотря на то, что исходная строка AFAIK содержит правильный начальный и конечный байты. Я проверил _Isleadbyte
массив в отладчике и это все нули. Так что эта ветвь, которая устанавливает длину ввода в 2
никогда не берется и вместо того, где длина установлена в 1
берется и, таким образом, MultiByteToWideChar()
терпит неудачу, потому что ведущий байт должен сопровождаться завершающим байтом.
Я даже проверил это C_936.NLS
присутствует в C:\Windows\System32\
, так что это не должно быть проблемой.
Итак, я предполагаю, что вопрос заключается в следующем: эта проблема на моем конце, с тестовым кодом, с настройкой ОС Windows, отсутствующими компонентами? Или это проблема в коде Visual Studio 2015?
ОБНОВИТЬ
Так что я случайно наткнулся на этот вопрос: не удается декодировать Shift-JIS с помощью wifstrem в Visual C++ 2013
Собственный ответ ОП показывает обходной путь:
const int oldMbcp = _getmbcp();
_setmbcp(932);
const std::locale locale("Japanese_Japan.932");
_setmbcp(oldMbcp);
Кажется, что тот же обходной путь работает для CP936, который я пытаюсь использовать.
ОБНОВЛЕНИЕ 2