Linux Driver(5) - container_of 分析定義如下:#define container_of(ptr, type, member) ({ \const typeof( ((type *)0)->member ) *__mptr = (ptr); \(type *)( (char *)__mptr - offsetof(type,member) );})一個看起來很複雜的巨集,這裡面有用到 offsetof,它是定義在stddef.h裡面,裡面的定義如下:/* Offset of member MEMBER in a struct of type TYPE. */#define offsetof(TYPE, MEMBER) 節能燈具__builtin_offsetof (TYPE, MEMBER)但不知__builtin_offsetof定義在那,上網找了一下,offset是定義如下:#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)主要就是為了取這個 member 在這個 struct 的偏移量。我們宣告一個 stuct 如下,並套用這個巨集,可得到 offset = 36 的結果。typedef struct _account_info{    int num;    char 景觀設計addr[32];    char name[32];    int serial;}account_info;size_t offset = offsetof(account_info, name);上一句在這例子中,如果不使用巨集的話,相等於以下三句:size_t offset = 0;account_info* infop = 0;offset = (size_t)(&infop->name);這樣應該就很清楚了,主要是後面二句,先宣告一個account_info的指標 infop,並指向0的位置。為何要這樣呢? 就是為了下面那一行,剛好賣房子可以用它來得到 name在account_info的相對位置。而以零當起始,算出來的才會是正確的偏移量。例如 account_info* infop = 10,那這裡 offset 就會變成不正確的 46。接下來就是 container_of 的分析了~~假設一下它的應用:void print_account_info(char* namep){    account_info* infop = container_of(namep, account_info, name);    printf("num=%d, addr=%s 裝潢name=%s\n", infop->num, infop->addr, infop->name, infop->serial);}int main(void){    account_info info;    info.num = 1;    strcpy(info.addr, "Taipei");    strcpy(info.name, "hughes");    info.serial = 2;        print_account_info(info.name);}吳哥窟由這例子可看出它的應用,就是由結構的成員指標得到結構指標~~接下來我們來模擬它的做法: account_info* infop; const typeof(infop->serial)* __mptr = &info.serial; infop = (__mptr - offsetof(account_info, serial)); printf("1. infop=%x, __mptr=%x, num=%d, addr=%s name=%s, serial=%d\n"            , infop, 永慶房屋__mptr, infop->num, infop->addr, infop->name, infop->serial); infop = ((char*)__mptr - offsetof(account_info, serial));    printf("2. infop=%x, __mptr=%x, num=%d, addr=%s name=%s, serial=%d\n"            , infop, __mptr, infop->num, infop->addr, infop->name, infop->serial);一開始先宣告591一個 const 的暫存指標,存這個struct的member的指標,在這個例子中就是 serial。typeof 是取出其型態的保留字,上面第二句等同這句 const int* __mptr = &info.serial。不過我並不了解這句的用意?如果有人知道可以告訴我,謝謝!!目前的想法有兩個,一是在核心中可能在某些情況下這指標會被改變,所以才要另存一個新的指標,而且要是const的,代表它不可被改變。二是是這防止巨集不小心改動到原來的指標內容,因為畢租房子竟是在kernel中,這樣是可能會讓系統crash的,使用 const可讓編譯器早一步提醒我們。似乎後者的可能較大點。接下來的 infop = (__mptr - offsetof(account_info, serial)) 才是重點,就是把這指標的位置往前移,移動多少呢?就是用前面提到的巨集 offsetof 來取出它在 struct 之中的偏移量,這樣就可把指標指向struct。原理其實就是簡單的數學,一元一次方程式啦~~~設 struct 指標為 sp,member 指標為 mp,mp 在 sp中的烤肉食材偏移量為 x。那麼 mp = sp + x ,mp 和 x 已知的情況下,當然可以求出 sp = mp - x。最後在上面的例子中可看出為何 infop 要轉型成 char*,因為不同類型的指標偏移量不同,在上面的例子中,如果像第一個不轉型的話,其 printf 印出來的值就會錯誤。算出來的偏移量,是要位移 1 才對,所以要轉型成char*。當然如果上面的例子是用 info.name 的話,就沒有差了。


.msgcontent .wsharing ul li { text-indent: 0; 信用卡代償}



分享

Facebook
Plurk
YAHOO!

創作者介紹

bubbles

ly49lyinea 發表在 痞客邦 PIXNET 留言(0) 人氣()