2

std::codecvt<wchar_t, char, std::mbstate_t>::in()Microsoft 標準ライブラリ実装 (MSVC11)を使用して、2 バイト コード ページでエンコードされた文字列を 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) を呼び出し、 の内部 (C?) 部分を渡し、std::localeで初期化されることがわかりました{_Page=932 _Mbcurmax=2 _Isclocale=0 ...}。問題) _Isleadbyte(unsigned char 型の) 32 個のゼロの配列に初期化されたメンバー。したがって、関数がリード バイトを処理するとき、この配列をチェックし、自然にこれがリード バイトではない'\x32'という (間違った) 結論に達します。そのため、喜んでWin-API 関数を呼び出しますが、もちろん半分の文字を変換することはできません。そのため、エラー コード -1 が返されます。これにより、多かれ少なかれコール スタックのすべてがキャンセルされ、最終的に 2 ( ) が返されます。MultiByteToWideChar()_Mbrtowc()std::codecvt_base::result::error

これは MS 標準ライブラリのバグですか (そのようです)? #ifdef(どのように)移植可能な方法で(つまり、最小量のsで)これを回避できますか?

4

2 に答える 2

1

あなたのコードを VC2010 / Windows 7 64 ビットにコピーして貼り付けました。

期待どおりに動作します。出力は次のとおりです。

Japanese_Japan.932
0
30a2

おそらくVC2012で導入されたバグです...

于 2013-07-14T11:25:26.143 に答える