[英]strlen performance implementation
这是一个多用途问题:
#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);
}
嗯,这个实现基于与您链接的 glibc 实现几乎相同的技巧( 确定一个字是否具有零字节)。 他们几乎做同样的事情,除了在 glibc 版本中一些循环被展开并且位掩码被明确地拼写出来。 您发布的代码中的ONES
和HIGHS
正是himagic = 0x80808080L
和lomagic = 0x01010101L
形成 glibc 版本。
我看到的唯一区别是 glibs 版本使用稍微不同的标准来检测零字节
if ((longword - lomagic) & himagic)
不做... & ~longword
HASZERO(x)
与HASZERO(x)
宏相比,它与x
做同样的事情,但还包括~(x)
成员)。 显然 glibc 的作者认为这个较短的公式更有效。 然而,它可能导致误报。 所以他们在if
下检查误报。
这确实是一个有趣的问题,哪个更有效:单阶段精确测试(您的代码)或两阶段测试,首先进行粗略的不精确检查,然后在必要时进行精确的第二次检查(glibc 代码)。
如果您想查看它们在实际性能方面的比较 - 在您的平台和数据上对它们进行计时。 没有别的办法。
另外,请注意,此实现可以在此处读取字符数组的末尾:
for (w = (const void *)s; !HASZERO(*w); w++);
因此依赖于未定义的行为。
为了回答你的第二个问题,我认为基于字节的原始strlen
实现将导致编译器更好的自动向量化,如果它很聪明并且支持向量指令集扩展(例如 SSE)已经启用(例如使用-msse
或适当的- -march
)。 不幸的是,即使编译器可以生成 32 位或 64 位伪矢量化代码,如问题中引用的 C 代码,如果它足够聪明,它也不会导致使用缺乏这些功能的基线 CPU 进行任何矢量化。 .
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.