当普通字符未签名时,计算UTF8中的字符数

时间:2013-01-09 10:06:38

标签: c unsigned-char

在UTF8中,我使用此函数来计算字符(而不是字节):

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

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

这适用于普通charunsigned char的实现吗?

3 个答案:

答案 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未签名,上述内容仍然有效。