【问题标题】:What is the fastest way to compare two strings in C?在 C 中比较两个字符串的最快方法是什么?
【发布时间】:2017-01-02 00:52:02
【问题描述】:

为了清楚起见,我只讨论以空字符结尾的字符串。

我熟悉在 C 中使用 strcmp 进行字符串比较的标准方法。但是我觉得它很慢而且效率低。

我不一定要寻找最简单但最有效的方法。

当前的比较方法(strcmp)能否在底层代码保持跨平台的情况下进一步优化?

如果 strcmp 无法进一步优化,我可以在没有 strcmp 的情况下执行字符串比较的最快方法是什么?

当前用例:

  • 判断两个任意字符串是否匹配
  • 字符串不超过 4096 字节,也不小于 1 字节
  • 在同一代码/库中分配/解除分配和比较字符串
  • 比较完成后,我会将字符串传递给另一个 C 库,该库需要格式为标准空终止格式
  • 系统内存限制不是一个大问题,但我会有数万个这样的字符串排队等待比较
  • 字符串可能包含高 ascii 字符集或 UTF-8 字符,但出于我的目的,我只需要知道它们是否匹配,内容不是问题
  • 应用程序在 x86 上运行,但也应在 x64 上运行

参考当前的 strcmp() 实现:

编辑:澄清解决方案不需要修改strcmp。

编辑 2:为此用例添加了具体示例。

【问题讨论】:

  • 为什么你认为strcmp()没有充分优化?
  • 我很确定 strcmp 已经针对您使用的任何平台进行了优化。
  • 我没有明确的答案,但我对此表示怀疑。您需要查看两个字符串的每个字符才能比较它们,我看不出有什么办法。我敢打赌 strcmp() 比“某个人”在一个下午能做的更好。
  • 我会证明通过真正的基准和拆解分析,然后再寻找修复一个失修的唯一证据是“感觉”的车轮。大多数平台都具有高度优化的内在函数来执行此类任务,前提是您为工具链启用了适当的优化配置。
  • 如果比较的字符串要么很短,要么很长且非常相似,您确实可以针对特定情况实施更好的比较。如果您必须多次将同一个字符串与其他字符串进行比较,您可能应该考虑使用散列,这样您就可以避免一遍又一遍地检查该常量字符串的内容。你需要告诉我们更多关于你在做什么,你发现 strcmp() 不够快的上下文。

标签: c string cross-platform c-strings strcmp


【解决方案1】:

恐怕您对strcmp()参考实施既不准确也不相关:

  • 这是不准确的,因为它使用 char 类型而不是 C11 标准中指定的 unsigned char 类型来比较字符:

    7.24.4 比较函数

    比较函数memcmpstrcmpstrncmp 返回的非零值的符号由第一对字符的值之间的差的符号决定(均解释为unsigned char ) 在被比较的对象上有所不同。

  • 这无关紧要,因为现代编译器使用的实际实现要复杂得多,使用手工编码的汇编语言进行内联扩展。

任何通用实现都可能不太理想,尤其是在编码为保持跨平台可移植性的情况下。

如果您的程序的瓶颈是比较字符串,这里有几个方向可以探索。

  • 分析您的算法,尝试找到减少比较次数的方法:例如,如果您在数组中搜索一个字符串,对该数组进行排序并使用二分搜索来大幅减少比较次数。
  • 如果您的字符串是在许多不同地方使用的标记,请分配这些标记的唯一副本并将它们用作标量值。当且仅当指针相等时,字符串才会相等。我一直在编译器和解释器中使用这个技巧和哈希表。
  • 如果您的字符串具有相同的已知长度,您可以使用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 lib strcmp?
  • 我确实喜欢使用固定长度字符串的 memcmp() 的想法,这可能有助于加快比较速度。
  • @JoshuaBriefman:编译器生成的代码实现了strcmp() 的标准定义。它可能会调用 C 库 strcmp() 实现或生成不调用的内联代码。
  • @rcgldr:较短的字符串 is 被认为更小,但不应为 memcmp() 提供长度小于其大小参数减一的字符串。 memcmp() 可以取消引用这些短字符串末尾之外的字节,并在某些系统上调用未定义的行为。例如memcmp(a, b, 8) 可以一次读取和比较 64 位。
  • @chqrlie 这是一个很好的例子,我可以看到使用结构来保存我的字符串如何有助于显着改善比较。如果我预计大多数字符串不匹配,那么我什至可以在开始哈希比较之前从结构中进行简单的长度比较,如果长度不匹配,我们会更快地失败。
猜你喜欢
  • 2012-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多