对于UTF8编码的中文,我们如果想要判断一个字符的长度,需要把它的起始码位提取出来并做比较。但是提取码位时,我们需要做正确的转换。
在如上的需求下,看下面的具体实例:
string s = "我";
s.length() == 3
如果直接取s[0]
做检测,如:
s[0] < 0x80
那么其结果必然为真。因为上述比较中,0x80被当作int的字面值,因此s[0]会隐式转换为 int, 而当作有符号数时,这是一个负数,扩展时使用符号位扩展的,所以其转换出来是一个绝对值特别大的负数!其自然小于正数0x80, 故结果变成真。显然这不是符合我们需要的。
因此,我们有两种方法可以解决这个问题:
第一:与上 0xff , 即 ( s[0] & 0xff )
这样虽然第一次是扩展为负数,但是做位运算时,符号位也会参与,故8位以上、前面所有的位都变成0,这样就成了一个正数、且值就是码位;
第二:显式转为unsigned char.
首先,转为unsigned char避免了char到int的扩展,所以不会有补1的情况。接着,signed 到 unsigned, 就是将最高位不再作为符号位了。所以能够得到预期的结果。
以下是测试代码:
int main(int argc, char *argv[])
{
string s = "我";
int k = -2000;
cout << (k & 0xff) << endl;
cout << boolalpha
<< (s[0] < 0x80) << endl
<< "to unsigned int : " << static_cast<unsigned int>(s[0]) << endl
<< "equals to 'static_cast<unsigned int>(static_cast<int>(s[0]))' : " << static_cast<unsigned int>(static_cast<int>(s[0])) << endl
<< "to unsigned char : " << static_cast<int>(static_cast<unsigned char>(s[0])) << endl // to int for display( else will display as char)
<< "to & : " << (s[0] & 0xff) << endl ;
return 0;
}
// output
48
true
to unsigned int : 4294967270
equals to 'static_cast<unsigned int>(static_cast<int>(s[0]))' : 4294967270
to unsigned char : 230
to & : 230