MSVC上的双字节编码(std :: codecvt):无法识别前导字节

时间:2013-06-15 09:47:45

标签: c++ windows visual-c++ unicode character-encoding

我想在Microsoft标准库实现(MSVC11)上使用std::codecvt<wchar_t, char, std::mbstate_t>::in()将双字节代码页中编码的字符串转换为UTF-16字符串。例如,请考虑以下程序:

#include <iostream>
#include <locale>

int main()
{
    // KATAKANA LETTER A (U+30A2) in Shift-JIS (Codepage 932)
    // http://msdn.microsoft.com/en-us/goglobal/cc305152
    char const cs[] = "\x83\x41";

    std::locale loc = std::locale("Japanese");

    // Output: "Japanese_Japan.932" (as expected)
    std::cout << loc.name() << '\n';

    typedef std::codecvt<wchar_t, char, std::mbstate_t> cvt_t;
    cvt_t const& codecvt = std::use_facet<cvt_t>(loc);
    wchar_t out = 0;
    std::mbstate_t mbst = std::mbstate_t();
    char const* mid;
    wchar_t* outmid;

    // Output: "2" (error) (expected: "0" (ok))
    std::cout << codecvt.in(
        mbst, cs,   cs + 2,   mid,
              &out, &out + 1, outmid) << '\n';

    // Output: "0" (expected: "30a2")
    std::cout << std::hex << out << '\n';
}

调试时,我发现in()最终调用内部_Mbrtowc()函数(crt \ src \ xmbtowc.c),传递{{1}的内部(C?)部分},用std::locale初始化,其中......代表(这似乎是问题){_Page=932 _Mbcurmax=2 _Isclocale=0 ...}成员,初始化为32个零的数组(unsigned char类型)。因此,当函数处理_Isleadbyte前导字节时,它会检查此数组并自然地得出(错误的)结论,即是一个前导字节。所以它很高兴地调用'\x32' Win-API函数,当然,它无法转换半角字符。因此,MultiByteToWideChar()返回错误代码-1,它会或多或少地取消调用堆栈中的所有内容,最终返回2(_Mbrtowc())。

这是MS标准库中的错误(看起来如此)? (如何)我可以通过便携方式解决这个问题(即std::codecvt_base::result::error s的用量最少?)

2 个答案:

答案 0 :(得分:1)

我将您的代码复制粘贴到VC2010 / Windows 7 64位中。

它按预期工作。这是输出:

Japanese_Japan.932
0
30a2

这可能是VC2012引入的一个错误......

答案 1 :(得分:1)

我在内部向微软报告。现在已经把它填充为一个新的bug(DevDiv#737880)。但我建议在http://connect.microsoft.com/VisualStudio

填写一个连接项