Linux 核心 list_head 以 typeof 與 container_of 實現極致泛型,但 typeof 為 GCC 延伸,非標準 C。本實作退而求其次:要求使用者將鏈表節點作為結構體第一個成員,以標準 C 實現型別無關的雙向鏈表。
// IList.h
#ifndef _I_LIST_H_
#define _I_LIST_H_
typedef struct _IList {
struct _IList *_prev;
struct _IList *_next;
} IList, *PIList;
// 初始化鏈表頭(頭節點自我指向)
#define IList_Init(pList) do { (pList)->_prev = (pList)->_next = (pList); } while(0)
// 插入新節點到 pLink 之前
#define IList_Insert(pLink, pNewLink) do { \
(pNewLink)->_prev = (pLink)->_prev; \
(pNewLink)->_next = (pLink); \
(pLink)->_prev->_next = (pNewLink); \
(pLink)->_prev = (pNewLink); \
} while(0)
// 刪除節點
#define IList_Remove(pLink) do { \
(pLink)->_prev->_next = (pLink)->_next; \
(pLink)->_next->_prev = (pLink)->_prev; \
(pLink)->_prev = (pLink)->_next = (pLink); \
} while(0)
// 遍歷宏(安全版,支援刪除當前節點)
#define IList_Foreach(pList, pos) \
for (pos = (pList)->_next; pos != (pList); pos = pos->_next)
#define IList_Foreach_Safe(pList, tmp, pos) \
for (pos = (pList)->_next, tmp = pos->_next; pos != (pList); pos = tmp, tmp = pos->_next)
// 取第 n 個節點(0-based)
PIList IList_Nth(PIList pList, int n);
#endif
// IList.c
#include "IList.h"
PIList IList_Nth(PIList pList, int n) {
PIList pLink = pList->_next;
int count = 0;
while (pLink != pList && count < n) {
pLink = pLink->_next;
count++;
}
return (pLink != pList) ? pLink : NULL;
}
// IListTest.c
#include <stdio.h>
#include <stdlib.h>
#include "IList.h"
typedef struct _Student {
IList link; // 必須是第一個成員
int id;
char name[32];
} Student;
int main(int argc, char *argv[]) {
if (argc < 2) return 1;
int num = atoi(argv[1]);
IList head;
IList_Init(&head);
for (int i = 0; i < num; ++i) {
Student *s = (Student*)malloc(sizeof(Student));
s->id = i + 1;
snprintf(s->name, sizeof(s->name), "Student_%d", s->id);
IList_Insert(&head, &s->link); // 插入到頭部
}
// 遍歷輸出
PIList pos;
IList_Foreach(&head, pos) {
Student *s = (Student*)pos; // 因 link 是第一成員,位址相同
printf("ID: %d, Name: %s\n", s->id, s->name);
}
// 安全刪除釋放
PIList tmp, pos2;
IList_Foreach_Safe(&head, tmp, pos2) {
Student *s = (Student*)pos2;
IList_Remove(pos2);
free(s);
}
return 0;
}
| 特性 | Linux list_head | 本實作 |
|---|---|---|
| 泛型機制 | typeof + container_of | 節點必須為第一成員 |
| 標準相容 | GCC 延伸 | 純標準 C (C89/C99) |
| 記憶體佈局 | 節點可嵌入任意位置 | 固定在結構體開頭 |
| 型別安全 | 編譯期檢查弱 | 同樣需手動轉型 |
雖失去 container_of 的靈活性,但以標準 C 實現核心邏輯,代碼清晰、可移植,是資源受限環境的優選方案。