c - 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的优化功能,但问题仍然存在。
解决方案
行为是正确的。
当
LC_CTYPE
使用的语言环境的类别来自 POSIX 语言环境时,这些函数的行为就像字符串已被转换为小写,然后执行字节比较一样。否则,结果未指定。
POSIX.1-2008 标准说明了这些功能:
当使用的语言环境的 LC_CTYPE 类别来自 POSIX 语言环境时,这些函数的行为就像字符串已转换为小写,然后执行字节比较。否则,结果未指定。
为什么?
正如@HansOlsson 在他的回答中指出的那样,仅在字母之间进行不区分大小写的比较并允许所有其他比较具有它们的“自然”结果,这strcmp()
会破坏排序。
if 'A' == 'a'
(不区分大小写比较的定义)then'_' > 'A'
和'_' < 'a'
(ASCII 字符集中的“自然”结果)不可能同时为真。
推荐阅读
- ios - 滑动删除应该删除该行并在 UITableView 中添加一个新行
- python - 如果第三列不同,熊猫数据框会删除两列上的重复项
- python - 读取制表符分隔的 ASCII 数据,变量由空行分隔
- swift - 如何将此 char* 转换为可选的字符串?使用 LibXL 中的 xlSheetReadStrA,检查空单元格
- node.js - 如何使用 nodejs child_process exec 捕获 ENOENT
- arm - 使用 Neon aarch64 优化 gemm(矩阵乘法)
- javascript - 使用 insertHTML (contenteditable) 为 execCommand 撤消/重做 iframe
- jquery - 将两个成功函数附加到 AJAX 调用(用于排队)
- asp.net - 字节转换成流
- java - 杰克逊自定义反序列化器仅获取列表 xml 中的最后一个值