C 語言無模板、無泛型關鍵字,但通過 void*(無類型指針)+ 顯式傳遞類型大小 + 函數指針回調,可實現類型無關的算法復用,效率接近專用版本。
void swap_int(int *a, int *b) {
int tmp = *a; *a = *b; *b = tmp;
}
// 錯誤:void* 無法解引用,編譯器不知大小
void swap_void(void *a, void *b) {
void tmp = *a; // error: void value not ignored
*a = *b;
*b = tmp;
}
#include <string.h>
void swap(void *a, void *b, size_t size) {
char *tmp = malloc(size);
memcpy(tmp, a, size);
memcpy(a, b, size);
memcpy(b, tmp, size);
free(tmp);
}
// 調用
int x = 1, y = 2;
swap(&x, &y, sizeof(int));
double u = 3.14, v = 2.71;
swap(&u, &v, sizeof(double));
int lsearch_int(int key, int arr[], int n) {
for (int i = 0; i < n; i++)
if (arr[i] == key) return i;
return -1;
}
void* lsearch(void *key, void *base, int n, size_t elemSize,
int (*cmp)(const void*, const void*, size_t)) {
for (int i = 0; i < n; i++) {
void *elem = (char*)base + i * elemSize;
if (cmp(key, elem, elemSize) == 0) return elem;
}
return NULL;
}
// int 比較器
int cmp_int(const void *a, const void *b, size_t sz) {
return *(int*)a - *(int*)b;
}
// 調用
int arr[] = {5, 2, 9, 1, 7};
int key = 9;
int *found = lsearch(&key, arr, 5, sizeof(int), cmp_int);
| 技術 | 作用 | 注意事項 |
|---|---|---|
void* | 擦除類型,統一接口 | 不能解引用,不能算術運算 |
size_t elemSize | 運行時獲取元素大小 | 調用者必須正確傳遞 sizeof(T) |
memcpy | 按字節複製內存 | 適用於 POD 類型,含指針的結構體需深拷貝 |
| 函數指針回調 | 將比較、複製、銷毀等語義外部化 | 簽名固定,實現解耦 |
(char*)base + i*elemSize | 手動計算元素地址 | 利用 char* 步長為 1 的特性 |
qsort:void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void*, const void*))bsearch:二分查找,同樣接口。stdlib.h 中的 lfind、lsearch(POSIX)。#define SWAP(a, b) do { \
typeof(a) _tmp = (a); \
(a) = (b); \
(b) = _tmp; \
} while(0) // GCC 擴展,編譯期類型安全
C 語言泛型編程的核心是「數據與操作分離」:用 void* 擦除數據類型,用函數指針參數化操作語義,用 sizeof 保留大小信息。這種思想正是 C++ 模板、Java 泛型、Go 接口的底層邏輯雛形。