以task_struct 為例來看
/*******task_struct 程序描述符**********************/
struct task_struct
struct list_head ;
/*********list_entry 函式使用(獲取鍊錶中的下乙個程序)***/
struct task_struct *task;
list_entry(task->tasks.next, struct task_struct, tasks)
/******list_entry 原始碼****************************/
#define list_entry(ptr, type, member) container_of(ptr, type, member)
#define container_of(ptr, type, member) ()
offsetof
(type,member)
((size_t) &((type *)0)->member)
//list_head是任務佇列,所有的tasks都掛在上面,linux 核心鍊錶中,不是在鍊錶結構中包含資料,而是在資料結構中包含鍊錶節點 list_head,鍊錶結構如下圖(原諒我拙劣的畫圖技術 ̄□ ̄||)
注意:這裡的鍊錶並不是指向下乙個或者上乙個元素的首位址。
看到這個結構,就可以想象怎麼獲得下乙個表首位址,先獲取下乙個表的list_head元素位址,然後找到元素相對於表首位址的偏移量,元素位址—偏移量 就是首位址。
下面來說原始碼實現過程:
&((type *)0)->member:
//把「0」強制轉化為指標型別,則該指標一定指向「0」位址因為指標是「type *」型的,所以可取到以「0」為基位址的乙個type型變數member域的位址。那麼這個位址也就等於member域到結構體基位址的偏移位元組數。
//也就是獲得tasks成員相對於task_struct結構體首位址的位址偏移量
//再來看 ((type )((char )(ptr)-(unsigned long)(&((type *)0)->member))):
//(char )(ptr)使得指標的加減操作步長為一位元組,(unsigned long)(&((type )0)->member)等於ptr指向的member到該member所在結構體基位址的偏移位元組數。二者一減便得出該結構體的位址。轉換為 (type )型的指標,大功告成。
//也就是說獲得tasks變數的位址,再減去偏移量,即得到task_struct結構體的首位址
//這樣就通過鍊錶節點得到了資料結構的位址
QT的TEST巨集實現機制
test x,y define test x,y gtest test x,y define gtest test x,y gtest test x,y,testing test,testing internal gettesttypeid define gtest test x,y,testing...
C C 中的assert 巨集 斷言機制
assert 是乙個除錯程式時經常使用的巨集,在程式執行時它計算括號內的表示式,如果表示式為false 0 程式將報告錯誤,並終止執行。如果表示式不為0,則繼續執行後面的語句。這個巨集通常原來判斷程式中是否出現了明顯非法的資料,如果出現了終止程式以免導致嚴重後果,同時也便於查詢錯誤。原型定義 inc...
MFC巨集訊息處理機制的原理
1.1 在mfc中處理訊息的函式是固定的,如afx msg int oncreate lpcreatestruct 這是乙個固定的,對應於on wm creat 巨集。如果改變了函式名,對應的巨集就會不認識。1.2 mycreate函式,用來響應系統的wm create訊息,這些函式是有固定格式要求...