首页 > 解决方案 > strcasecmp 算法有缺陷吗?

问题描述

我正在尝试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;
}

输出:

-1  # "A" is less than "_"
1   # "a" is more than "_"
2   # "A" is more than "_" with strcasecmp ???
2   # "a" is more than "_" with strcasecmp

看来,如果当前字符 ins1是一个字母,它总是被转换为小写,不管当前字符 ins2是否是一个字母。

有人可以解释这种行为吗?第一行和第三行不应该相同吗?

先感谢您!

PS:
gcc 9.2.0在 Manjaro 上使用。
此外,当我使用-fno-builtin标志编译时,我得到的是:

-30
2
2
2

我猜是因为程序没有使用gcc的优化功能,但问题仍然存在。

标签: cstrcmp

解决方案


行为是正确的。

根据POSIXstr\[n\]casecmp()规范

LC_CTYPE使用的语言环境的类别来自 POSIX 语言环境时,这些函数的行为就像字符串已被转换为小写,然后执行字节比较一样。否则,结果未指定。

这也是Linux 手册页NOTES部分的一部分:

POSIX.1-2008 标准说明了这些功能:

当使用的语言环境的 LC_CTYPE 类别来自 POSIX 语言环境时,这些函数的行为就像字符串已转换为小写,然后执行字节比较。否则,结果未指定。

为什么?

正如@HansOlsson 在他的回答中指出的那样,仅在字母之间进行不区分大小写的比较并允许所有其他比较具有它们的“自然”结果,这strcmp()会破坏排序。

if 'A' == 'a'(不区分大小写比较的定义)then'_' > 'A''_' < 'a'(ASCII 字符集中的“自然”结果)不可能同时为真。


推荐阅读