標準級實現
void* memcpy(void* dest, const void* src, size_t count)
{
// 1. src 加 const:承諾不修改源數據
char* pdest = (char*)dest;
const char* psrc = (const char*)src;
// 2. 保存原始 dest 用於返回,支持鏈式調用
void* ret = dest;
// 3. 重疊檢測:dest 在 src 區間內,且 dest > src(向上重疊)
if (pdest > psrc && pdest < psrc + count) {
// 從尾部向前複製,避免覆蓋未讀數據
pdest += count - 1;
psrc += count - 1;
while (count--) *pdest-- = *psrc--;
} else {
// 正常情況:從頭向後複製
while (count--) *pdest++ = *psrc++;
}
return ret; // 5. 返回原始 dest
}
五大關鍵點解析
- const 正確性:
const void* src 防止誤寫源數據,允許傳入字符串常量、只讀內存。
- 字節級操作:轉為
char* 逐字節複製,符合 C 標準「字符類型可訪問任意對象表示」。
- 重疊安全:
- dest < src:向前複製安全(如 memcpy(buf, buf+2, 10))。
- src 且重疊:必須向後複製(如 memcpy(buf+2, buf, 10))。
- 標準庫 memmove 保證處理所有重疊;memcpy 行為未定義,**但優質實現通常內建重疊檢測**。
- 保存返回值:
ret 保存原始 dest,因複製過程中 pdest 已移動。支持 strcat(memcpy(dst, src, n), tail) 等鏈式調用。
- 性能優化(生產級):
- 位對齊檢測 → 以 uintptr_t/uint64_t 塊複製(8/16 字節)。
- SIMD 指令集(SSE/AVX/NEON)向量化。
- 預取指令、非時序存儲。
- 小塊專用展開、大塊頁對齊優化。
面試手寫版掌握邏輯正確性即可,工程中直接用編譯器內建/庫函數。
memcpy vs memmove vs strcpy
| 函數 | 重疊行為 | 終止條件 | 返回值 | 典型用途 |
| memcpy | 未定義(實現常處理) | 計數 count | dest | 二進制塊複製,已知長度 |
| memmove | 保證安全 | 計數 count | dest | 可能重疊的塊複製 |
| strcpy | 未定義 | 遇 '\0' | dest | C 字符串複製 |
| strncpy | 未定義 | 計數 或 '\0' | dest | 固定寬度字符串(不保證以 '\0' 結尾) |
面試/考試常見陷阱題
// 錯誤:未處理重疊,且未返回 dest
void* bad_memcpy(void* d, const void* s, size_t n) {
char* pd = (char*)d; const char* ps = (const char*)s;
while (n--) *pd++ = *ps++;
// 缺 return d;
}
// 錯誤:重疊判斷條件寫反
if (pdest < psrc && pdest + count > psrc) // 應為 pdest > psrc && pdest < psrc + count
// 錯誤:直接用 int* 複製,違反嚴格別名規則,可能導致誤優化
while (count >= 4) { *(int*)pdest = *(int*)psrc; ... }