std::codecvt<wchar_t, char, std::mbstate_t>::in()
我想使用Microsoft 标准库实现 (MSVC11)将在双字节代码页中编码的字符串转换为 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
成员,初始化为 32 个零的数组(无符号字符类型)。因此,当函数处理'\x32'
前导字节时,它会检查这个数组并自然得出(错误的)结论,即这不是前导字节。所以它愉快地调用了MultiByteToWideChar()
Win-API 函数,当然,它不能转换半角字符。因此,_Mbrtowc()
返回错误代码 -1,这或多或少取消了调用堆栈上的所有内容,最终std::codecvt_base::result::error
返回 2 ( )。
这是 MS 标准库中的错误吗(看起来是这样)?(如何)我可以以可移植的方式解决这个问题(即使用最少的#ifdef
s)?