[英]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.