1. 程式人生 > >關於宏:container_of和 offsetof以及list_for_each_entry

關於宏:container_of和 offsetof以及list_for_each_entry

set style member 分析 0地址 typeof 判斷 開始 fine

1.offsetof(TYPE, MEMBER)

 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

offsetof是一個自定義的宏,其返回值是一個member成員在一個type類型的結構體中相對於結構體首地址的字節偏移量;

分析其工作原理:
1.(TYPE *)0將0地址強制轉換成TYPE *類型指針---------且可以認為,這個類型的結構體的首地址是0x0;
2.(TYPE *)0->MEMBER以指針形式訪問成員MEMBER;
3.&((TYPE *)0->MEMBER)取成員MEMBER的地址;


因為是從0地址開始的,所以取得成員變量MEMBER的地址等於=相對與結構體首地址的偏移地址;
4.((size_t) &((TYPE *)0)->MEMBER),然後將強制類型轉換成int型,作為offsetof的返回值;

2.container_of

#define container_of(ptr, type, member) ({ const typeof( ((type *)0)->member ) * __mptr = (ptr);(type *)( (char *)__mptr - offsetof(type,member) );})

作用:根據一個結構體變量中的一個域成員變量的指針(也就是地址)來獲取指向整個結構體變量的指針(地址)的功能


分析:
1).const typeof( ((type *)0)->member ) * __mptr = (ptr)
  typeof( ((type *)0)->member )這裏獲得member成員的類型
  typeof()就是由變量名得到變量數據類型的;
2).const typeof( ((type *)0)->member ) * __mptr = (ptr)

  定義一個const typeof() * __mptr類型的指針,並初始化為ptr;這裏的ptr是一個指向type類型結構體成員變量member的指針,也就是member在結構體中的地址;


3).(char *)__mptr

  這裏將__mptr指針強制類型轉換成char *類型:
  原因是: 如果_mptr為int *類型, _mptr - offset 相當於減去 sizeof(int)*offset個字節;
4).offsetof(type,member)

  就是一個得到member相當於結構體首地址的偏移量,以字節單位;
5).(char *)__mptr - offsetof(type,member)
  得到_mptr所在結構體的首地址;
6).(type *)( (char *)__mptr - offsetof(type,member))
  將得到的結構體首地址強制類型轉換成type *類型;

3.list_for_each_entry

#define list_for_each_entry(pos, head, member)                    for (pos = list_entry((head)->next, typeof(*pos), member);             prefetch(pos->member.next), &pos->member != (head);              pos = list_entry(pos->member.next, typeof(*pos), member))

在這裏,list_for_each_entry就是一個for循環:

for ( pos = list_entry((head)->next, typeof(*pos), member); prefetch(pos->member.next), &pos->member != (head); pos = list_entry(pos->member.next, typeof(*pos), member))
1) pos = list_entry((head)->next, typeof(*pos), member)

  其中:

  #define list_entry(ptr, type, member) container_of(ptr, type, member)  

  因此:

  pos = list_entry((head)->next, typeof(*pos), member)
  等價於:
  pos = container_of((head)->next, typeof(*pos), member)

  所以:pos被初始化為一個指向 結構體成員變量member所在的結構體(結構體類型為typeof(*pos)) 的指針;

  由於container_of的第一個參數是head->next,所以被初始化的pos是指向頭結點的下一個節點;

 2) prefetch(pos->member.next), &pos->member != (head)

  判斷是否又到達頭結點,表明遍歷結束

 3) pos = list_entry(pos->member.next, typeof(*pos), member)

   是pos指向下一個鏈表節點;

關於宏:container_of和 offsetof以及list_for_each_entry