2013-01-09 38 views
2

在UTF8我使用计数使用此功能字符(而不是字节):Count个字符时的char是无符号

int schars(const char *s) 
{ 
    int i = 0; 

    while (*s) { 
     if ((*s & 0xc0) != 0x80) i++; 
     s++; 
    } 
    return i; 
} 

是否在实施这项工作,其中纯charunsigned char

+0

有趣的是,几乎没有相关的事实:默认情况下,普通'char' *是gcc下的* unsigned char'。在MSVC下,它是'signed char'。按照标准,'char','unsigned char'和'signed char'是三种不同的类型。 – Corbin

+1

@Corbin我认为普通的'char'是gcc上的'signed char' –

+0

可能已经发誓gcc默认签名,但看起来你是对的。哎呀:)。 – Corbin

回答

2

它应该。

您只使用二元运算符,它们的功能相同,不管底层数据类型是带符号还是无符号。唯一的例外可能是!=操作,但你可以用&取代这个,然后拥抱整个事情有!,鼻翼:

!((*s & 0xc0) & 0x80) 

,然后你必须完全二元运算符。

您可以通过检查ANSI C Standard的第3.3.10节来验证字符是否升级为整数,其中指出“每个[按位与]的操作数都应具有整数类型。”

编辑

我修改我的答案。按位操作不作为无符号签署一样,按照ANSI C标准的3.3:

一些运营商(单目运算符〜和二元运算< <,>>,&,^和|, 统称为按位运算符)应具有整型的操作数。 这些运算符返回值取决于整数的内部表示, 因此对于签名类型具有实现定义的方面

实际上,对带符号整数执行按位运算被列为可能的安全漏洞here

在Visual Studio编译器中,有符号和无符号的处理方式相同(请参阅here)。

由于this SO question讨论,最好使用unsigned char来进行字节式的内存读取和内存操作。

+0

感谢理查德,这就是我认为的 –

+0

@DavidRF,我一直在思考这个问题,现在我不太确定我的答案。如果你正在阅读'unsigned char',那么一切都会很好。事实上,我不确定当你在'signed char'上执行'&'时会发生什么。我试图找出如何做一个安全的转换。 – Richard

+0

是的,“Ramón”返回4而不是5使用'!((* s&0xc0)&0x80)',感谢您的建议 –

1

是的,它会的。

*s将在计算发生之前被提升为int。所以,你的代码就相当于:

if (((int) *s & 0xC0) != 0x80) i++; 

而且上面会工作,即使char是无符号。

+1

严格来说,文字0xC0和0x80已经是'int'类型,所以唯一的提升就是* s被转换为int的那个。 – Lundin

+0

@Lundin,你说得对,没有'char'文字。回答更新相应,谢谢:) –

+0

(在C++中,它们将是char类型)然而, – Lundin

3

char未签名时,它的工作原理与它签名时一样。

在这两个有符号的补码表示和无符号表示,第8和UTF8编码单元的第7位是10当且仅当该代码单元是码点的第一个代码单元。因此,您要为每个代码点的第一个代码单元计数1。

int不能保证是一个足够大的类型包含在每个字符串中的字符数,但我以为你不关心;-)

“性格”是潜在的含糊的字眼。此代码计算Unicode代码点,这与可显示字符(“字素”)不同。有时,多个代码点代表单个字形,例如,在组合标记用于重音时。关于知道Unicode字符串中有多少个代码点的唯一实际用途是计算编码为UTF-32时占用的字节数。如果你小心,你可以确保唯一需要处理“字符”的代码是字体引擎,再加上一些复杂的操作,如Unicode规范化和字符编码。

+0

谢谢史蒂夫,是的,size_t是一个更好的选择,但我使用'int'来避免每次调用 –

相关问题