我們在編寫驅動程序的時候,會經常在open函數中用到container_of宏,那麼這個在linux內核中這個宏的主要作用是什麼呢?
所在linux目錄
tool\perf\util\include\linux\Kernel.h
主要功能
首先簡述一下container_of的主要功能:對於給定結構體成員的地址,從而找到該結構體的首地址。換句話說就是,如果已經知道了一個結構體成員的地址,那麼通過container_of函數就可以知道該結構體的入口地址,也就是首地址啦。
參數分析
首先看一下container_of的表達式:container_of(ptr,type,member),從表達式可以看出container_of宏一共需要三個參數,下面分別介紹:
ptr: 結構體成員的地址或者指針
type: 結構體類型
member: 成員名稱
通過這三個參數,就可以返回該結構體的首地址了。
例子分析
結構體
struct test
{
int i;
int j;
char k;
};
Struct test temp;
現在呢,如果我想通過temp.j的地址找到結構體temp的首地址,就可以使用我們的container_of宏。
container_of(&temp.j, struct test, j);
源代碼分析
首先來看一下我們的源代碼:
#define container_of(ptr, type, member) ({ \
const typeof(((type *)0)->member) * __mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); })
#endif
第一段代碼是:
const typeof(((type *)0)->member) * __mptr = (ptr);
這裏linux內核使用了一個typeof函數,typeof是GNU對標準C的擴展,它的作用是根據變量獲取變量類型,而(type )0則表示type結構體指針0的成員變量member,因此typeof(((type )0)->member)則表示member的變量類型,從而_mptr就表示爲member類型的指針變量,同時指向ptr指針,也就是說將ptr指向的地址賦給了_member指針變量。
我們再來看第二句代碼:
(type *)((char *)__mptr - offsetof(type, member));
這句代碼相對比較複雜,我們詳細分析下,首先由左邊的( type * ),我們知道這條代碼的返回值類型爲type指針類型。而對於((char *)__mptr - offsetof(type, member)),我們要了解offsetof的作用。
offsetof的表達式爲offsetof(TYPE, MEMBER),表示爲type與member的相對地址差。因此我們便知道了((char *)__mptr - offsetof(type, member))表示_mptr地址減去type與member的相對地址差,從而得到結構體type的首地址。