#define list_entry(ptr, type, member) \ container_of(ptr, type, member)
#define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );})
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
size_t 是unsigned long typedef struct xxx { type1 member; ……(结构体中其他域) }type; 定义变量: type a; type * b; type1 * ptr;
&((type *)0)->member取得的是个什么,为什么要转为u long 为什么要用__mptr当中间变量,不直接用ptr。 最后用char型的__mptr减ulong的偏移量可以得到该结构体的地址吗?
首先第一个问题是 通过 typeof( ((type *)0)->member ) 获取member成员的类型, 第二个问题是 如果直接用ptr 做偏移, ptr本身指向就变了 第三个问题是 获取到的是这个结构起始地址
2. 为什么需要中间变量_mtpr,因为传入的参数ptr,不见得就是个简单的指针变量,也有可能是个表达式(因为这是宏)。 比如contailer_of(ptr + 1, struct XXX, member), 如果去掉_mptr,那么就变成了(char *)ptr + 1 - offset,结果就是错误的(应该是((char *)(ptr + 1)) - offset,注意括号)
3. 为什么要转换成char *,因为在c语言里面,(((type *)ptr) - offset) == ((char *)ptr) - sizeof(type) * offset。 不是往前挪offset个字节,而是往前挪offset个结构。 显然这些需要的是字节语义。
因为 成员的地址 = 结构的地址 + 字节偏移, 所以 结构的地址 = 成员的地址 - 字节编译。(以字节为单位计算)
|