我正在尝试strcasecmp用 C重新实现该函数,但我注意到比较过程中似乎存在不一致之处。
从 man strcmp
strcmp() 函数比较两个字符串 s1 和 s2。不考虑区域设置(有关区域设置的比较,请参阅 strcoll(3))。如果发现 s1 分别小于、匹配或大于 s2,则它返回一个小于、等于或大于零的整数。
从 man strcasecmp
strcasecmp() 函数对字符串 s1 和 s2 执行逐字节比较,忽略字符的大小写。如果发现 s1 分别小于、匹配或大于 s2,则它返回一个小于、等于或大于零的整数。
int strcmp(const char *s1, const char *s2);
int strcasecmp(const char *s1, const char *s2);
鉴于此信息,我不明白以下代码的结果:
#include <stdio.h>
#include <string.h>
int main()
{
// ASCII values
// 'A' = 65
// '_' = 95
// 'a' = 97
printf("%i\n", strcmp("A", "_"));
printf("%i\n", strcmp("a", "_"));
printf("%i\n", strcasecmp("A", "_"));
printf("%i\n", strcasecmp("a", "_"));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
-1 # "A" is less than "_"
1 # "a" is more than "_"
2 # "A" is more than "_" with strcasecmp ???
2 # "a" is more than "_" with strcasecmp
Run Code Online (Sandbox Code Playgroud)
看来,如果当前输入的字符s1是字母,不管当前输入的字符是否是字母,它总是被转换为小写s2。
有人可以解释这种行为吗?第一行和第三行不应该相同吗?
先感谢您!
PS:
我gcc 9.2.0在 Manjaro 上使用。
另外,当我用-fno-builtin标志编译时,我得到:
-30
2
2
2
Run Code Online (Sandbox Code Playgroud)
我猜是因为该程序没有使用gcc的优化功能,但问题仍然存在。
And*_*nle 30
行为是正确的。
当
LC_CTYPE使用的语言环境类别来自 POSIX 语言环境时,这些函数的行为就像字符串已被转换为小写,然后执行字节比较。否则,结果是不确定的。
POSIX.1-2008 标准描述了这些函数:
当使用的语言环境的 LC_CTYPE 类别来自 POSIX 语言环境时,这些函数的行为就像字符串已转换为小写,然后执行字节比较。否则,结果是不确定的。
为什么?
正如@HansOlsson 在他的回答中指出的那样,仅在字母之间进行不区分大小写的比较,并允许所有其他比较具有它们的“自然”结果,这strcmp()会破坏排序。
如果'A' == 'a'(不区分大小写的比较的定义)那么'_' > 'A'和'_' < 'a'(ASCII 字符集中的“自然”结果)不能都为真。
Han*_*son 21
其他链接,http: //man7.org/linux/man-pages/man3/strcasecmp.3p.html 的 strcasecmp 说转换为小写是正确的行为(至少在 POSIX 语言环境中)。
这种行为的原因是,如果您使用 strcasecmp 对字符串数组进行排序,则需要获得合理的结果。
否则,如果您尝试使用例如 qsort 对“A”、“C”、“_”、“b”进行排序,结果将取决于比较的顺序。
看起来,如果 s1 中的当前字符是一个字母,它总是被转换为小写,而不管 s2 中的当前字符是否是一个字母。
这是正确的 - 这就是strcasecmp()函数应该做的!它是一个POSIX函数,而不是C标准的一部分,而是来自“ The Open Group Base Specifications, Issue 6 ”:
在 POSIX 语言环境中, strcasecmp() 和 strncasecmp() 的行为就像将字符串转换为小写然后执行字节比较一样。结果在其他语言环境中未指定。
顺便说一句,此行为也与_stricmp()函数有关(如 Visual Studio/MSCV 中使用的):
_stricmp 函数在将每个字符转换为小写后依次比较 string1 和 string2,并返回一个表示它们关系的值。