在open函數中,int (*open) (struct inode *inode,strcut file *flip); inode->i_cdev結構包含了我們在註冊時配置的cdev結構,但是我們實際真正需要的是包含cdev結構的scull結構,在open中,我們應當獲得這個scull結構的指針,方便以後的操作。如何獲得,要利用到container_of宏。
該宏定義在<linux/kernel.h>中
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
typeof 用於確定某個變量的實際類型,offsetof宏用於確定某個成員在結構體中的偏移值。
第一句話,僅僅是用來定義一個跟member同類型的指針,這裏可理解爲臨時變量。我們在定義一個宏時,如果也需要和參數相同的臨時變量,就可以採用這種方法。這裏的(type*)0,假定有一個在0地址的type類型指針,因爲這不牽涉到讀寫,所以安全上沒有問題。這裏的0可以爲任意都可以,在這裏僅僅是獲得變量類型,它和下面的offsetof宏不同。
第二句話:用member的地址減去member在type中的偏移,就得到了包含這個member的type的首地址。
offsetof宏定義在[include/linux/stddef.h]中:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
這裏的技巧是假定有一個在0地址的TYPE類型指針,那麼將它的MEMBER地址獲得,並轉爲size_t(int)類型,這就是MEMBER的偏移了。很巧妙的思路。