在UTF8中,我使用此函数来计算字符(而不是字节):
int schars(const char *s)
{
int i = 0;
while (*s) {
if ((*s & 0xc0) != 0x80) i++;
s++;
}
return i;
}
这适用于普通char
为unsigned char
的实现吗?
答案 0 :(得分:3)
当char
未签名时,它也可以正常工作。
在带符号的2的补码表示和无符号表示中,当且仅当代码单元不时,UTF8代码单元的第8和第7位为10
代码点的代码单元。所以你为每个代码点的第一个代码单元计算1。
int
不能保证足够大,以包含每个字符串中的字符数,但我认为你不在乎; - )
“人物”可能是一个含糊不清的术语。此代码计算Unicode代码点,这与可显示字符(“字形”)不同。有时,多个代码点代表单个字素,例如,当组合标记用于重音时。关于知道Unicode字符串中有多少代码点的唯一实际用途是计算编码为UTF-32时占用的字节数。如果你小心,你可以确保唯一需要处理“字符”的代码是字体引擎,以及一些复杂的操作,如Unicode规范化和字符编码。
答案 1 :(得分:2)
应该。
您只使用二元运算符,无论基础数据类型是有符号还是无符号,它们的功能都相同。唯一的例外可能是!=
运算符,但您可以将其替换为&
,然后用!
,ala:
!((*s & 0xc0) & 0x80)
然后你只有二元运算符。
您可以通过检查ANSI C Standard的第3.3.10节来验证字符是否被提升为整数,这表示“[按位AND]的每个操作数都应具有整数类型。”
修改强>
我修改了我的答案。按照ANSI C标准中的3.3,按位操作与无符号操作不同,无符号操作:
一些运算符(一元运算符〜,二元运算符<<,>>,&,^和|, 统称为按位运算符)应具有具有整数类型的操作数。 这些运营商回归 取决于整数的内部表示的值,和 因此,对于签名类型,实现定义方面。
实际上,对有符号整数执行按位运算被列为可能的安全漏洞here。
在Visual Studio编译器中,对signed和unsigned进行相同的处理(参见here)。
正如this SO question所讨论的那样,最好使用unsigned char
进行内存的字节读取和内存操作。
答案 2 :(得分:1)
是的,它会。
在进行计算之前, *s
将被提升为int
。所以,你的代码相当于:
if (((int) *s & 0xC0) != 0x80) i++;
即使char
未签名,上述内容仍然有效。