在linux核心中實現了幾種常用的資料結構包括:鍊錶、佇列、對映、二叉樹。
一、鍊錶
在一般需要遍歷所有資料或需要動態的加入和刪除資料時選用鍊錶比較適合,當需要隨機訪問資料時一般不使用鍊錶。linux核心中煉表的實現不同於通常的設計,它不是將資料塞入鍊錶,而是將鍊錶節點塞入資料結構。
通常的方法:
struct fox;
而linux中的方法為:struct list_head;
struct fox;
我們可以通過下圖看出具體的差別,通過下面兩個圖,我們可以清楚的看出下面的方法即linux核心中的實現的方法更具有拓展性。然後我們使用list來構建乙個雙向鍊錶,但是這個鍊錶的指標怎麼訪問struct fox的成員呢?下面我們看一下linux核心中如何實現的。
linux中通過下面兩個巨集來實現:
#define container_of(ptr,type,member) ()
#define list_entry(ptr,type,member) container_of(ptr,type,member)
通過list_entry方法,核心提供了建立、操作以及其他鍊錶管理的各種例程,所有方法不需要知道list_head所嵌入物件的資料結構。
我們參看中的定義,並知道如何使用。
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
下面分析一下這個巨集:
1. const typeof( ((type *)0)->member ) *__mptr = (ptr);
是定義乙個__mptr指標變數,型別和member的型別一樣typeof是獲得乙個變數的型別,((type *)0)->member 則是tpye型別中的member 變數,一般type為結構體型別,member 則為其中的變數這裡的0只是作為乙個臨時的指標位址用,任何可以表示位址的數字都可以代替0。
2. #define offsetof(type, member) ((size_t) &((type *)0)->member)
是獲取type型別中成員member的相對偏移量,如果基址為0,那麼位址&((type *)0)->member轉換為size_t後就是此成員的偏移量了,這裡的0作為起始位址用,來計算偏移量,如果用其它數字代替offsetof得到的數值要減去這個數字才是真正的偏移量,所以這裡用0是最佳的選擇。
下面使用簡單的程式測試這個巨集是否如上面分析一樣。
#include #include #include #define offsetof(type,member) ((size_t)&((type*)0)->member)
#define container_of(ptr,type,member) ()
struct fox;
int main()
輸出結果為
8
linux核心系列 二 核心資料結構之鍊錶
傳統鍊錶與linu核心鍊錶的區別圖 圖一 圖二從上圖中看出在傳統鍊錶中各種不同鍊錶間沒有通用性,因為各個資料域不同,而在linux核心中巧妙將鍊錶結構內嵌到資料域結構中使得不同結構之間能連線起來 核心中煉表實現檔案路徑 include linux list.h 鍊錶結構定義 struct list ...
核心資料結構之對映
對映也稱之為關聯陣列,它是一組唯一鍵的集合,每個鍵與特定的值相關。一般支援至少三個操作 linux提供了乙個簡單而有效的對映資料結構,它不是通用目的的對映,而是為特殊用例設計的 將uid 唯一標識號 對映到乙個指標。除了提供三個主要的對映操作,還基於add操作的基礎上提供了乙個allocate操作。...
資料結構之核心鍊錶
核心鍊錶設計的非常巧妙,但也不是什麼難理解的內容,關於核心鍊錶的介紹網上有很多,這裡就不贅述了,來個使用的例子吧。list.h ifndef hs kernel list h define hs kernel list h define offsetof type,member size t typ...