为什么在将窄字符串转换为宽字符串时用0xFF屏蔽字符?

Why mask a char with 0xFF when converting narrow string to wide string?

本文关键字:字符串 0xFF 屏蔽 字符 转换 为什么      更新时间:2023-10-16

考虑将窄字符串转换为宽字符串的函数:

std::wstring convert(const std::string& input)
{
try
{
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
return converter.from_bytes(input);
}
catch(std::range_error& e)
{
std::size_t length = input.length();
std::wstring result;
result.reserve(length);
for(std::size_t i = 0; i < length; i++)
{
result.push_back(input[i] & 0xFF);
}
return result;
}
}

我很难理解回退路径中对这个表达式的需求:

result.push_back(input[i] & 0xFF);

为什么字符串中的每个字符都用 0xFF (0b11111111) 屏蔽?

使用0xFF掩码会将任何负值减少到 0-255 范围内。

例如,如果您的平台char是表示 ISO-8859-1 字符的 8 位签名类型,而您的wchar_t表示 UCS-2、UTF-16 或 UCS-4,则这是合理的。


如果没有这种更正(或类似的东西,例如转换为unsigned charstd::byte),您会发现字符在提升到更广泛的类型时是符号扩展的。

示例:0xa9(Unicode 和 Latin-1 中的©,有符号 8 位中的 -87)将变为uffa9而不是u00a9


我认为将char转换为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"xc2xa3xc2xa9 おはよう") << std::endl;
// Latin-1: 壩
std::wcout << convert("xc2xa3xa9") << std::endl;
}

输出:

£© おはよう
壩

看起来在转换失败时,代码只需将string复制到 char 的wstring字符中即可尝试自己的转换。

& 0FF旨在"清理"任何高于 255 的值以适应(扩展的)ASCII 表。但是,这是一个无操作,因为input[i]返回charsizeof(char) == 1这意味着无论如何 255 都是最大值(在CHAR_BIT == 8char == unsigned char的情况下)。

等效的只是使用构造函数立即复制它们:

std::wstring result(input.begin(), input.end());