標準實現
size_t my_strlen(const char *str) {
if (!str) return 0; // 防護空指針
const char *p = str;
while (*p) ++p; // 指針推進尋找\0
return p - str; // 指針相減得長度
}
變體實現對比
| 版本 | 代碼 | 特點 |
| 數組下標 | size_t i=0; while(str[i])++i; return i; | 直觀,隱含乘法(按sizeof計算) |
| 指針遞增 | while(*str++); return str - p - 1; | 經典教科書寫法,副作用修改參數 |
| for循環緊湊 | const char *s; for(s=str; *s; ++s); return s-str; | 無副作用,現代風格推薦 |
| 標準庫實現 | GCC glibc 使用SIMD向量化,按字塊(64B)掃描\0 | 極速,針對對齊/非對齊分支 |
關鍵細節深度解析
1. 返回類型 size_t
- 無符號類型,匹配內存地址空間(32位4GB,64位16EB)
- 避免負長度邏輯錯誤
- 格式化輸出用
%zu (C99)
2. 參數 const char *
- 承諾不修改內容,允許傳入字符串字面量
- 內部用
const char *遍歷,保持const正確性
3. 空指針處理策略
// 策略A:返回0(防崩潰,掩蓋bug)
if (!str) return 0;
// 策略B:斷言失敗(暴露bug,調試階段推薦)
assert(str != NULL);
// 策略C:未定義行為(標準庫行為,最高性能)
// 直接 dereference NULL → SIGSEGV
4. 編譯器優化視角
// 編譯器可能優化為:
size_t my_strlen(const char *str) {
return __builtin_strlen(str); // 內聯SIMD指令序列
}
- 常量字符串長度編譯期計算:
strlen("hello") → 常數5
- 循環不變量外提、向量化、循環展開
- 鏈接時優化(LTO)可消除函數調用開銷
測試用例
int main() {
const char *tests[] = {
"", "a", "hello", "中文測試", NULL
};
for (int i = 0; tests[i]; ++i) {
printf("'%s' -> len=%zu, std=%zu\n",
tests[i], my_strlen(tests[i]), strlen(tests[i]));
}
// 空指針測試(策略A)
printf("NULL -> %zu\n", my_strlen(NULL));
return 0;
}
面試延伸問題
- 不使用庫函數實現
strcpy/strcmp/strchr —— 同樣指針算術核心
- 計算UTF-8字符串字符數(非字節數) —— 需解碼多字節序列
- 檢測字符串是否為合法UTF-8 —— 狀態機校驗字節模式
- 線程安全的strlen —— 純讀操作天然線程安全,無共享寫入