container_of宏用于根据已知结构体某个成员的地址得到整个结构体变量的地址,宏定义如下:
#define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );})
例如:
#define to_i2c_driver(d) container_of(d, struct i2c_driver, driver) static int i2c_device_match(struct device *dev, struct device_driver *drv) { /* ... */ struct i2c_driver *driver = to_i2c_driver(drv); /* ... */ }
1. typeof
typeof关键字是gcc对c的一个扩展,用于获取变量的类型,例如:
char ch; typeof (ch) *chptr; /* 相当于char *chptr */所以这里也仅仅是定义了一个结构体中某个成员的指针,然后将ptr赋值给这个指针。
2. offsetof
offsetof宏用于取得结构体成员在结构体中的偏移,定义在<linux/stddef.h>中:
#undef offsetof #ifdef __compiler_offsetof #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER) #else #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #endif
那么是如何取得这个偏移的呢?(TYPE *)0使用0这个地址强制转换成一个结构体类型的指针,然后取得结构体某个成员的地址并将其转换成size_t类型,这样就得到了结构体成语在结构体中的偏移。那为什么说这个地址就是结构体成员的偏移呢?结构体成员的偏移本身应该是结构体成员的地址减去结构体变量的地址,而结构体变量的地址现在是0地址,所以结构体成员地址就等于其偏移。
在得到这个偏移之后,再用结构体成员的实际地址减去这个偏移就得到结构体变量的地址,最后将这个地址转换成结构体类型的指针并返回。