掩蔽用0xFF
将任何负值减少到 0-255 范围内。
这是合理的,例如,如果您的平台char
是代表 ISO-8859-1 字符的 8 位有符号类型,并且您的wchar_t
代表 UCS-2、UTF-16 或 UCS-4。
如果没有此更正(或类似的操作,例如转换为unsigned char
or std::byte
),您会发现当提升为更宽的类型时,字符会被符号扩展。
示例:0xa9(©
在 Unicode 和 Latin-1 中,-87 在有符号 8 位中)将变为\uffa9
代替\u00a9
.
我认为转换更清楚char
to an unsigned char
- 适用于任何大小的字符,并更好地传达意图。您可以直接更改该表达式,或创建一个codecvt
为您正在做的事情命名的子类。
以下是如何编写和使用最小的codecvt
(仅适用于窄→宽转换):
#include <codecvt>
#include <locale>
#include <string>
class codecvt_latin1 : public std::codecvt<wchar_t,char,std::mbstate_t>
{
protected:
virtual result do_in(std::mbstate_t&,
const char* from,
const char* from_end,
const char*& from_next,
wchar_t* to,
wchar_t* to_end,
wchar_t*& to_next) const override
{
while (from != from_end && to != to_end)
*to++ = (unsigned char)*from++;
from_next = from;
to_next = to;
return result::ok;
}
};
std::wstring convert(const std::string& input)
{
using codecvt_utf8 = std::codecvt_utf8<wchar_t>;
try {
return std::wstring_convert<codecvt_utf8>().from_bytes(input);
} catch (std::range_error&) {
return std::wstring_convert<codecvt_latin1>{}.from_bytes(input);
}
}
#include <iostream>
int main()
{
std::locale::global(std::locale{""});
// UTF-8: £© おはよう
std::wcout << convert(u8"\xc2\xa3\xc2\xa9 おはよう") << std::endl;
// Latin-1: 壩
std::wcout << convert("\xc2\xa3\xa9") << std::endl;
}
Output:
£© おはよう
壩