在 C 中比较两个字符串的最快方法是什么?
What is the fastest way to compare two strings in C?
为清楚起见,我只讨论空终止字符串。
我熟悉在 C 中使用 strcmp 进行字符串比较的标准方法。但是我觉得速度慢,效率低。
我不一定要寻找最简单的方法,但要寻找最有效的方法。
能否在底层代码保持跨平台的情况下进一步优化当前的比较方法(strcmp)?
如果 strcmp 无法进一步优化,在没有 strcmp 的情况下执行字符串比较的最快方法是什么?
当前用例:
- 判断两个任意字符串是否匹配
- 字符串不会超过 4096 字节,大小也不会小于 1 字节
- 字符串是 allocated/deallocated 并在相同的 code/library
中进行比较
- 比较完成后,我会将字符串传递给另一个 C 库,该库需要格式为标准的空终止格式
- 系统内存限制不是一个大问题,但我会有数万个这样的字符串排队等待比较
- 字符串可能包含高位 ascii 字符集或 UTF-8 字符,但出于我的目的,我只需要知道它们是否匹配,内容不是问题
- 应用程序 运行 在 x86 上,但也应该 运行 在 x64 上
对当前 strcmp() 实现的引用:
- How does strcmp work?
- What does strcmp actually do?
- GLIBC strcmp() source code
编辑:澄清解决方案不需要修改 strcmp。
编辑 2:为此用例添加了具体示例。
恐怕您对 strcmp()
的 参考实施 既不准确也不相关:
它是不准确的,因为它使用 char
类型而不是 C11 标准中指定的 unsigned char
类型来比较字符:
7.24.4 Comparison functions
The sign of a nonzero value returned by the comparison functions memcmp
, strcmp
, and strncmp
is determined by the sign of the difference between the values of the first pair of characters (both interpreted as unsigned char
) that differ in the objects being compared.
这无关紧要,因为现代编译器使用的实际实现要复杂得多,使用手工编码的汇编语言扩展内联。
任何通用实现都可能不是最优的,特别是如果编码为跨平台table。
如果您的程序的瓶颈是比较字符串,这里有几个探索方向。
- 分析你的算法,尝试找到减少比较次数的方法:例如,如果你在一个数组中搜索一个字符串,对该数组进行排序并使用二进制搜索来大大减少比较次数。
- 如果您的字符串是在许多不同地方使用的标记,请分配这些标记的唯一副本并将它们用作标量值。当且仅当指针相等时,字符串才相等。我一直在编译器和解释器中使用散列 table.
这个技巧
- 如果您的字符串具有相同的已知长度,您可以使用
memcmp()
而不是 strcmp()
。 memcmp()
比 strcmp()
更简单,并且可以在已知字符串正确对齐的地方更有效地实现。
编辑: 使用提供的额外信息,您可以为字符串使用这样的结构:
typedef struct string_t {
size_t len;
size_t hash; // optional
char str[]; // flexible array, use [1] for pre-c99 compilers
} string_t;
你这样分配这个结构:
string_t *create_str(const char *s) {
size_t len = strlen(s);
string_t *str = malloc(sizeof(*str) + len + 1;
str->len = len;
str->hash = hash_str(s, len);
memcpy(str->str, s, len + 1);
return str;
}
如果你可以对你所有的字符串使用这些str东西,你可以通过首先比较长度或哈希值来大大提高匹配效率。您仍然可以将 str
成员传递给您的库函数,它以 null 结尾。
为清楚起见,我只讨论空终止字符串。
我熟悉在 C 中使用 strcmp 进行字符串比较的标准方法。但是我觉得速度慢,效率低。
我不一定要寻找最简单的方法,但要寻找最有效的方法。
能否在底层代码保持跨平台的情况下进一步优化当前的比较方法(strcmp)?
如果 strcmp 无法进一步优化,在没有 strcmp 的情况下执行字符串比较的最快方法是什么?
当前用例:
- 判断两个任意字符串是否匹配
- 字符串不会超过 4096 字节,大小也不会小于 1 字节
- 字符串是 allocated/deallocated 并在相同的 code/library 中进行比较
- 比较完成后,我会将字符串传递给另一个 C 库,该库需要格式为标准的空终止格式
- 系统内存限制不是一个大问题,但我会有数万个这样的字符串排队等待比较
- 字符串可能包含高位 ascii 字符集或 UTF-8 字符,但出于我的目的,我只需要知道它们是否匹配,内容不是问题
- 应用程序 运行 在 x86 上,但也应该 运行 在 x64 上
对当前 strcmp() 实现的引用:
- How does strcmp work?
- What does strcmp actually do?
- GLIBC strcmp() source code
编辑:澄清解决方案不需要修改 strcmp。
编辑 2:为此用例添加了具体示例。
恐怕您对 strcmp()
的 参考实施 既不准确也不相关:
它是不准确的,因为它使用
char
类型而不是 C11 标准中指定的unsigned char
类型来比较字符:7.24.4 Comparison functions
The sign of a nonzero value returned by the comparison functions
memcmp
,strcmp
, andstrncmp
is determined by the sign of the difference between the values of the first pair of characters (both interpreted asunsigned char
) that differ in the objects being compared.这无关紧要,因为现代编译器使用的实际实现要复杂得多,使用手工编码的汇编语言扩展内联。
任何通用实现都可能不是最优的,特别是如果编码为跨平台table。
如果您的程序的瓶颈是比较字符串,这里有几个探索方向。
- 分析你的算法,尝试找到减少比较次数的方法:例如,如果你在一个数组中搜索一个字符串,对该数组进行排序并使用二进制搜索来大大减少比较次数。
- 如果您的字符串是在许多不同地方使用的标记,请分配这些标记的唯一副本并将它们用作标量值。当且仅当指针相等时,字符串才相等。我一直在编译器和解释器中使用散列 table. 这个技巧
- 如果您的字符串具有相同的已知长度,您可以使用
memcmp()
而不是strcmp()
。memcmp()
比strcmp()
更简单,并且可以在已知字符串正确对齐的地方更有效地实现。
编辑: 使用提供的额外信息,您可以为字符串使用这样的结构:
typedef struct string_t {
size_t len;
size_t hash; // optional
char str[]; // flexible array, use [1] for pre-c99 compilers
} string_t;
你这样分配这个结构:
string_t *create_str(const char *s) {
size_t len = strlen(s);
string_t *str = malloc(sizeof(*str) + len + 1;
str->len = len;
str->hash = hash_str(s, len);
memcpy(str->str, s, len + 1);
return str;
}
如果你可以对你所有的字符串使用这些str东西,你可以通过首先比较长度或哈希值来大大提高匹配效率。您仍然可以将 str
成员传递给您的库函数,它以 null 结尾。