在UTF8我使用计数使用此功能字符(而不是字节):Count个字符时的char是无符号
int schars(const char *s)
{
int i = 0;
while (*s) {
if ((*s & 0xc0) != 0x80) i++;
s++;
}
return i;
}
是否在实施这项工作,其中纯char
是unsigned char
?
在UTF8我使用计数使用此功能字符(而不是字节):Count个字符时的char是无符号
int schars(const char *s)
{
int i = 0;
while (*s) {
if ((*s & 0xc0) != 0x80) i++;
s++;
}
return i;
}
是否在实施这项工作,其中纯char
是unsigned char
?
它应该。
您只使用二元运算符,它们的功能相同,不管底层数据类型是带符号还是无符号。唯一的例外可能是!=
操作,但你可以用&
取代这个,然后拥抱整个事情有!
,鼻翼:
!((*s & 0xc0) & 0x80)
,然后你必须完全二元运算符。
您可以通过检查ANSI C Standard的第3.3.10节来验证字符是否升级为整数,其中指出“每个[按位与]的操作数都应具有整数类型。”
编辑
我修改我的答案。按位操作不作为无符号签署一样,按照ANSI C标准的3.3:
一些运营商(单目运算符〜和二元运算< <,>>,&,^和|, 统称为按位运算符)应具有整型的操作数。 这些运算符返回值取决于整数的内部表示, 因此对于签名类型具有实现定义的方面。
实际上,对带符号整数执行按位运算被列为可能的安全漏洞here。
在Visual Studio编译器中,有符号和无符号的处理方式相同(请参阅here)。
由于this SO question讨论,最好使用unsigned char
来进行字节式的内存读取和内存操作。
感谢理查德,这就是我认为的 –
@DavidRF,我一直在思考这个问题,现在我不太确定我的答案。如果你正在阅读'unsigned char',那么一切都会很好。事实上,我不确定当你在'signed char'上执行'&'时会发生什么。我试图找出如何做一个安全的转换。 – Richard
是的,“Ramón”返回4而不是5使用'!((* s&0xc0)&0x80)',感谢您的建议 –
当char
未签名时,它的工作原理与它签名时一样。
在这两个有符号的补码表示和无符号表示,第8和UTF8编码单元的第7位是10
当且仅当该代码单元是不码点的第一个代码单元。因此,您要为每个代码点的第一个代码单元计数1。
int
不能保证是一个足够大的类型包含在每个字符串中的字符数,但我以为你不关心;-)
“性格”是潜在的含糊的字眼。此代码计算Unicode代码点,这与可显示字符(“字素”)不同。有时,多个代码点代表单个字形,例如,在组合标记用于重音时。关于知道Unicode字符串中有多少个代码点的唯一实际用途是计算编码为UTF-32时占用的字节数。如果你小心,你可以确保唯一需要处理“字符”的代码是字体引擎,再加上一些复杂的操作,如Unicode规范化和字符编码。
谢谢史蒂夫,是的,size_t是一个更好的选择,但我使用'int'来避免每次调用 –
有趣的是,几乎没有相关的事实:默认情况下,普通'char' *是gcc下的* unsigned char'。在MSVC下,它是'signed char'。按照标准,'char','unsigned char'和'signed char'是三种不同的类型。 – Corbin
@Corbin我认为普通的'char'是gcc上的'signed char' –
可能已经发誓gcc默认签名,但看起来你是对的。哎呀:)。 – Corbin