如何在 C 中跨平台比较单个多字节字符常量?

How do I compare single multibyte character constants cross-platform in C?

中,我找到了使用 C++ 字符串执行此操作的解决方案,但我想知道在 C 中是否也有使用 char 的解决方案。

我当前的解决方案使用 str.compare()size() 中的字符串,如 中所示。

现在,由于我在 std::string 中只使用一个(多字节)字符,是否可以使用 char 实现相同的效果?

例如,if( str[i] == '¶' )?我如何使用 char's 实现?

(编辑:在 SO 上为评论中指出的比较运算符创建了一个类型)

我相信你的意思是这样的:

char a = '¶';
char b = '¶';

if (a == b) /*do something*/;

以上可能有效也可能无效,如果 '¶' 的值大于字符范围,则它会溢出,导致 a b 存储一个与'¶' 不同的值。不管它们持有哪个值,它们实际上可能都具有相同的值。

记住,char 类型只是一个单字节宽(8 位)整数,因此为了处理多字节字符并避免溢出,您只需使用更宽的整数类型 (短、​​整数、长...).

short a = '¶';
short b = '¶';

if (a == b) /*do something*/;

根据个人经验,我还注意到,有时您的环境可能会尝试使用与您需要的不同的字符编码。例如,尝试打印 'á' 字符实际上会产生其他内容。

unsigned char x = 'á';
putchar(x); //actually prints character 'ß' in console.
putchar(160); //will print 'á'.

发生这种情况是因为控制台使用扩展 ASCII 编码,而我的编码环境实际上使用 Unicode,为 'á' 解析值 225 而不是我想要的值 160。

How do I compare single multibyte character constants cross-platform in C?

您似乎是指使用单个多字节字符表示的整数字符常量。那么,首先要认识到的是,在 C 中,整数字符常量(示例:'c''¶')的类型为 int,而不是 char。 C17 的主要相关部分是第 6.4.4.4/10 段:

An integer character constant has type int. The value of an integer character constant containing a single character that maps to a single-byte execution character is the numerical value of the representation of the mapped character interpreted as an integer. The value of an integer character constant containing more than one character (e.g.,’ab’ ), or containing a character or escape sequence that does not map to a single-byte execution character, is implementation-defined. If an integer character constant contains a single character or escape sequence, its value is the one that results when an object with type char whose value is that of the single character or escape sequence is converted to type int.

(强调已添加。)

请注意,“定义的实现”意味着从一开始就具有有限的可移植性。即使我们排除了定义不当行为的实现,我们仍然有其他选择,例如

  • 实现拒绝包含多字节源字符的整数字符常量;或
  • 实现拒绝不映射到单字节执行字符的整数字符常量;或
  • 无论字节序列在执行字符集中的重要性如何,实现都通过字节标识映射映射源多字节字符。

这不是一个详尽的列表。

您当然可以将整数字符常量相互比较,但是如果它们映射到多字节执行字符,那么您就无法将它们与单个 char 进行有效比较。

由于您的预期应用似乎是在 C 字符串中定位单个多字节字符,最自然的做法似乎是使用标准 strstr() 实现 C++ 方法的 C 模拟功能。示例:

    char str[] = "Some string ¶ some text ¶ to see";
    char char_to_compare[] = "¶";
    int char_size = sizeof(char_to_compare) - 1;  // don't count the string terminator

    for (char *location = strstr(str, char_to_compare);
            location;
            location = strstr(location + char_size, char_to_compare)) {
        puts("Found!");
    }

在很多情况下这会做正确的事情,但它仍然对于某些执行字符编码中的某些字符可能是错误的,例如那些具有多个移位状态的编码。

如果您想要对基本执行字符集之外的字符进行稳健处理,那么您最好控制内存中的编码,并对该编码执行适当的转换、操作和转换.例如,这主要是 ICU 所做的。