typeof & offset_of & container of
一、typeof
关键字typeof用于获取表达式的数据类型。属于 GNU 对 C 语言的扩展。使用了此关键字,其他的编译器就不一定可以正常编译你的代码。
https://gcc.gnu.org/onlinedocs/gcc-4.6.2/gcc/C-Extensions.html#C-Extensions
- /* linux-2.6.38.8/include/linux/kernel.h */
- #define min(x, y) ({ \
- typeof(x) _min1 = (x); \
- typeof(y) _min2 = (y); \
- (void) (&_min1 == &_min2); \ // 对实际的逻辑不产生任何影响。作用是保证x,y 是相同的数据类型。
//怎么保证? 不是相同数据类型,编译器会报错误。如下面图
- _min1 < _min2 ? _min1 : _min2; })
- #define max(x, y) ({ \
- typeof(x) _max1 = (x); \
- typeof(y) _max2 = (y); \
- (void) (&_max1 == &_max2); \
- _max1 > _max2 ? _max1 : _max2; })
二、offsetof
#define offsetof(TYPE, MEMBER) ( (size_t) &((TYPE*)0)->MEMBER)
把 0 地址初始化为一个对象的起始地址,之后再取里面的某个元素的地址。得到的就是这个元素相对于结构体头的偏移。返回类型是size_t
三、container_of
#define container_of(ptr,type,member) ({ \
const typeof( ((type*)0)->member )* __mptr = (ptr); \
(type*)( (char*)__mptr - offsetof(type,member) );})
最后返回的是 type* 类型的指针,指针的地址就是 (char*)ptr - offsetof(type,member) ;
offsetof宏:先将空指针0转换为一个指向struct pid的指针,然后获取成员的地址,因为是从0开始的,所以这个地址就是成员相对于struct pid结构的偏移量。
因为内存的使用是往上增长的,所以成员自己的地址减去成员在结构中的偏移量就是结构实例的地址了。
这个宏是内核的一个使用技巧,很多地方都是这样根据成员的地址然后找到结构实例的地址。