strlen性能实现

时间:2012-08-03 00:45:33

标签: c string performance strlen

这是一个多功能问题:

  • 这与glibc strlen实施相比如何?
  • 对于一般情况和自动向量化,是否有更好的方法。

随机填充垃圾,因为stackoverflow以某种方式比我更了解代码到汇总比率

#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <stdbool.h>
#include <stdlib.h>

/* Todo: Document */
#define WORD_ONES_LOW   ((size_t)-1 / UCHAR_MAX)
#define WORD_ONES_HIGH  (((size_t)-1 / UCHAR_MAX) << (CHAR_BIT - 1))

/*@doc
 * @desc: see if an arch word has a zero
 * #param: w - string aligned to word size
 */
static inline bool word_has_zero(const size_t *w)
{
    return ((*w - WORD_ONES_LOW) & ~*w & WORD_ONES_HIGH);
}

/*@doc
 * @desc: see POSIX strlen()
 * @param: s - string
 */
size_t strlen(const char *s)
{
    const char *z = s;

    /* Align to word size */
    for (; ((uintptr_t)s & (sizeof(size_t) - 1)) && *s != '\0'; s++);

    if (*s != '\0') {
        const size_t *w;

        for (w = (const size_t *)s; !word_has_zero(w); w++);
        for (s = (const char *)w; *s != '\0'; s++);
    }

    return (s - z);
}

3 个答案:

答案 0 :(得分:7)

嗯,这个实现基于与你链接的glibc实现几乎相同的技巧(Determine if a word has a zero byte)。它们几乎完全相同,除了在glibc版本中,一些循环被展开并且位掩码被明确地拼写出来。您发布的代码中的ONESHIGHS正好是himagic = 0x80808080Llomagic = 0x01010101L形成了glibc版本。

我看到的唯一区别是glibs版本使用稍微不同的标准来检测零字节

if ((longword - lomagic) & himagic)

没有... & ~longword(与您的示例中的HASZERO(x)宏相比,它与x做同样的事情,但也包括~(x)成员。显然,glibc的作者认为这种较短的公式更有效。但它可能导致误报。因此,他们会检查if下的误报。

这确实是一个有趣的问题,更有效的:单阶段精确测试(您的代码)或两阶段测试,以粗略的不精确检查开始,如有必要,通过精确的第二次检查(glibc代码) )。

如果您想了解他们如何在实际效果方面进行比较 - 在​​您的平台和数据上计算时间。别无他法。

答案 1 :(得分:3)

另外,请注意这个实现可以在这里读取char数组的结尾:

for (w = (const void *)s; !HASZERO(*w); w++);

因此依赖于未定义的行为。

答案 2 :(得分:0)

为了回答你的第二个问题,我认为天真的基于字节的strlen实现将导致编译器更好的自动向量化,如果它是智能的并且已经启用了对向量指令集扩展(例如SSE)的支持(例如,使用-msse或适当的-march)。不幸的是,它不会导致任何带有缺少这些功能的基线cpus的矢量化,即使编译器可能生成32位或64位伪矢量化代码,如问题中引用的C代码,如果它足够聪明......