2

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

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

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

这是否适用于 plainchar的实现unsigned char

4

3 回答 3

3

它在未签名时和char已签名时一样有效。

在有符号 2 的补码表示和无符号表示中,UTF8 代码单元的第 8 位和第 7 位10当且仅当代码单元不是代码点的第一个代码单元时。因此,您为每个代码点的第一个代码单元计算 1。

int不保证是一个足够大的类型来包含每个字符串中的字符数,但我假设你不在乎;-)

“字符”可能是一个模棱两可的术语。此代码计算 Unicode 代码点,这与可显示字符(“字形”)不同。有时多个代码点代表一个字素,例如当组合标记用于重音时。了解 Unicode 字符串中有多少个代码点的唯一实际用途是计算编码为 UTF-32 时它将占用多少字节。如果您小心,您可以确保唯一需要处理“字符”的代码是字体引擎,以及一些复杂的操作,例如 Unicode 规范化和字符编码。

于 2013-01-09T10:16:01.867 回答
2

它应该。

您只使用二元运算符,并且无论底层数据类型是有符号还是无符号,它们的功能都相同。唯一的例外可能是!=运算符,但您可以用 a 替换它&,然后用 a 来包含整个事物!,ala:

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

然后你只有二元运算符。

您可以通过检查ANSI C 标准的第 3.3.10 节来验证字符是否提升为整数,该节规定“每个操作数 [按位与] 都应具有整数类型。”

编辑

我修改我的答案。根据 ANSI C 标准的 3.3,有符号的位运算与无符号的位运算不同:

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

事实上,对有符号整数执行按位运算在这里被列为可能的安全漏洞。

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

正如这个 SO question所讨论的,最好使用unsigned char按字节读取内存和操作内存。

于 2013-01-09T10:15:48.770 回答
1

是的,它会的。

*sint在计算发生之前提升。因此,您的代码相当于:

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

即使char未签名,上述内容也将起作用。

于 2013-01-09T10:13:56.573 回答