3

如果第一个字符串大于第二个字符串,我认为 strcmp 应该返回一个正数。但是这个节目

#include <stdio.h>
#include <string.h>

int main()
{
    char A[] = "A";
    char Aumlaut[] = "Ä";
    printf("%i\n", A[0]);
    printf("%i\n", Aumlaut[0]);
    printf("%i\n", strcmp(A, Aumlaut));
    return 0;
}

打印65,-61-1.

为什么?有什么我忽略的吗?
我想也许我保存为 UTF-8 的事实会影响事情。你知道,因为Ä那里由 2 个字符组成。但是保存为 8 位编码并确保字符串的长度都为 1 并没有帮助,最终结果是相同的。
我究竟做错了什么?

在此处使用 32 位 Linux 下的 GCC 4.3,以防万一。

4

6 回答 6

2

strcmp而其他字符串函数实际上并不支持 utf。在大多数 posix 机器上,C/C++char内部是 utf8,这使得大多数事情在读写方面“正常工作”,并提供库理解和操作 utf 代码点的选项。但是默认string.h函数对文化不敏感,并且不知道任何关于比较 utf 字符串的事情。您可以查看源代码strcmp并亲自查看,它是尽可能幼稚的实现(这意味着它也比国际化感知比较函数更快)。

我刚刚在另一个问题中回答了这个问题——你需要使用一个支持 UTF 的字符串库,比如 IBM 优秀的ICU - International Components for Unicode

于 2012-05-04T08:36:13.347 回答
1

保存为 8 位 ASCII 编码,'A' == 65如果'Ä'您认为它是unsigned char. 无论如何,'Ä'严格来说是正数并且大于 2^7-1,你只是在打印它,就好像它已经签名一样。

如果你认为'Ä'是一个unsigned char(它是),它的值在你的字符集中是 195。因此,strcmp(65, 195)正确报告-1.

于 2012-05-04T08:38:35.567 回答
1

strcmp() 将字符作为无符号 ASCII 值。所以,你的双点 A 不是 char -61,而是 char 195(或者可能是 196,如果我的数学错误的话)。

于 2012-05-04T08:41:23.010 回答
1

和类似的strcmp比较函数将字符串中的字节视为unsigned chars,如第 7.24.4 节第 1 节中的标准所指定(在 C99 中为 7.21.4)

比较函数 memcmp、strcmp 和 strncmp 返回的非零值的符号由被比较对象中不同的第一对字符(均解释为无符号字符)的值之间的差异符号确定。

(强调我的)。

原因可能是这样的解释保持了公共编码中代码点之间的顺序,而将它们解释为有符号char的 s 则没有。

于 2012-05-04T09:50:22.760 回答
0

Check the strcmp manpage:

The strcmp() function compares the two strings s1 and s2. It returns
an integer less than, equal to, or greater than zero if s1 is found,
respectively, to be less than, to match, or be greater than s2.
于 2012-05-04T08:44:33.090 回答
-1

当输入字符集超过 UTF8 时,要在 C 中正确处理字符串,您应该使用标准库的宽字符工具来处理字符串和 i/o。你的程序应该是:

#include <wchar.h>
#include <stdio.h>

int main()
{
    wchar_t A[] = L"A";
    wchar_t Aumlaut[] = L"Ä";
    wprintf(L"%i\n", A[0]);
    wprintf(L"%i\n", Aumlaut[0]);
    wprintf(L"%i\n", wcscmp(A, Aumlaut));
    return 0;
}

然后它会给出正确的结果(GCC 4.6.3)。你不需要一个特殊的图书馆。

于 2012-05-04T09:07:22.997 回答