首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

dietlibc strcpy 算法淺析:字長級拷貝與對齊檢查的極簡實現

     編輯:關於C語言

前言

dietlibc 是一個極小的 C 標準庫(適合嵌入式/靜態鏈接),其 `strcpy` 實現同樣採用**字長級拷貝**,但代碼極度精簡,僅 30 行。本文通過還原宏為函數,逐步剖析其對齊檢查、字長拷貝主循環、尾部處理邏輯。

核心代碼 (還原後)


#include <stdint.h>
#include <string.h>

// 1. 構造魔數:0x01010101 / 0x80808080
static inline uint32_t MKW(uint32_t x) {
    return x | (x << 8) | (x << 16) | (x << 24);
}

// 2. 計算指針對齊所需填充字節 (0~3)
static inline size_t STRALIGN(uintptr_t p) {
    size_t r = p & 3;
    return r ? 4 - r : 0;
}

// 3. 檢查源/目標指針是否同樣對齊
static inline int UNALIGNED(uintptr_t dst, uintptr_t src) {
    return ((dst ^ src) & 3) != 0;
}

// 4. 取字長低字節
#define GFC(x) ((x) & 0xFF)
// 6. 字長右移 8 位 (移至下一字節)
#define INCSTR(x) do { (x) >>= 8; } while (0)

char* strcpy2(char* dst, const char* src) {
    char* res = dst;
    uint32_t l;

    // A. 指針未對齊或互不對齊 → 退回逐字節
    if (UNALIGNED((uintptr_t)dst, (uintptr_t)src)) {
        while ((*dst++ = *src++));
        return res;
    }

    // B. 目標指針未對齊 → 逐字節填充至對齊
    size_t mis = STRALIGN((uintptr_t)dst);
    while (mis-- && (*dst++ = *src++));
    if (mis != (size_t)-1) return res;  // 已遇 \0

    // C. 主循環:字長級拷貝
    while (1) {
        l = *(const uint32_t*)src;  // 載入 4 字節

        // 檢測是否含 \0 (同 GLIBC 魔數法)
        if ((((l - MKW(0x01)) & ~l) & MKW(0x80)) != 0) {
            // 含 \0:逐字節完成剩餘
            do { *dst++ = GFC(l); INCSTR(l); } while (GFC(l));
            return res;
        }

        // 無 \0:整字長寫入,指針 +4
        *(uint32_t*)dst = l;
        src += 4;
        dst += 4;
    }
}

關鍵邏輯圖解

輸入: src="Hello World\0", dst=buffer

1. UNALIGNED 檢查: src%4==0 && dst%4==0? 是 → 進入字長路徑
2. STRALIGN(dst)=0 → 無需填充
3. 主循環:
   l = "Hell" (0x6C6C6548)
   零檢測: 否 → *(uint32_t*)dst = l; src+=4; dst+=4
   l = "o Wo" → 同理
   l = "rld\0" → 零檢測: 是
       進入尾部處理:
       *dst++ = 'r'; l>>=8
       *dst++ = 'l'; l>>=8
       *dst++ = 'd'; l>>=8
       *dst++ = '\0'; l>>=8 → GFC(l)=0 結束

對齊檢查必要性

  • **硬體要求**:許多架構 (SPARC, MIPS, ARM 舊版) 要求 `uint32_t*` 訪問地址 4 字節對齊,否則 SIGBUS。
  • **效能**:x86 雖支援非對齊訪問,但跨緩存行/頁面時極慢。
  • **邏輯正確性**:`UNALIGNED` 確保源/目標**相對對齊** (差值為 4 的倍數),否則字長寫入會錯位覆蓋相鄰數據。

與 GLIBC strcmp 異同

特性dietlibc strcpyGLIBC strcpy
代碼行數~30~100+ (含向量化路徑)
架構專用優化無 (純 C)有 (SSE2/AVX2/NEON 汇编)
對齊處理填充至對齊類似 + 向量對齊
零檢測魔數0x01/0x80相同
目標場景嵌入式/靜態鏈接/極小體積通用高效能

實測驗證 (文章截圖說明)

作者在 VS 调试器中人為將 `src`/`dst` +1 導致未對齊,觀察到代碼正確退回逐字節路徑,驗證對齊檢查邏輯有效。

適用性與遷移建議

  • ✅ **嵌入式/裸機/啟動器**:代碼極小、無依賴、易審計。
  • ⚠️ **通用應用**:直接用 GLIBC/musl,向量化版本在長字符串上快 5-10x。
  • 🔧 **移植到 64 位**:將 `uint32_t` → `uint64_t`,魔數擴展為 `0x0101...` (8 字節),`STRALIGN` 模 8,性能雙倍。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved