list_entry(ptr, type, member)语句理解
list_entry(ptr, type, member)语句定义在文件include/linux/list.h中。
00342: /**
00343: *list_entry-getthestructforthisentry
00344: *@ptr:the&structlist_headpointer.
00345: *@type:thetypeofthestructthisisembeddedin.
00346: *@member:thenameofthelist_structwithinthestruct.
00347: */
00348: #definelist_entry(ptr, type, member)\
00349: container_of(ptr,type,member)
00350:
而container_of()宏定义在文件include/linux/kernel.h。
00670: /**
00671: *container_of-castamemberofastructureouttothecontainingstructure
00672: *@ptr:thepointertothemember.
00673: *@type:thetypeofthecontainerstructthisisembeddedin.
00674: *@member:thenameofthememberwithinthestruct.
00675: *
00676: */
00677: #definecontainer_of(ptr, type, member)({ \
00678: consttypeof(((type*)0)–>member)*__mptr=(ptr); \
00679: (type*)((char*)__mptr–offsetof(type,member));})
list_entry(ptr, type, member)宏的含义为:已知指针ptr所指向的地址,通过ptr所指向的地址来计算其所属数据结构的起始地址(ptr的指针类型和member是同一种数据结构,在这里就是struct list_head结构类型,现在是内核中的双链表,这种思想也可以用在其他数据结构种)。
将地址0转换为type类型的指针。
如我们可以将数据结构struct page应用到这里。
(struct page *)0;
很多人对这条语句感到困惑,一般我们程序中不能访问地址0的,那怎么能够将地址0转换为type类型的指针呢?这条语句是否符合语法,是否正确?
不同进程看到的地址空间是不一样的,具体类型取决于进程访问的方式。前面我们提到类型强制性转换,就是可以将任何地址强制性转换为某种数据类型。对于进程来说,不一定能够访问0地址(访问0地址是违法的),但只要不去访问0地址,我们把地址转换为任何类型都是没问题的。怎样想与怎样去做是两回事,可以把地址0想象为任何数据类型,但只要不去做(访问地址0),那就没有任何问题。
offsetof()宏定义在文件include/linux/stddef.h。
00020: #undefoffsetof
00021: #ifdef__compiler_offsetof
00022: #defineoffsetof(TYPE,MEMBER)__compiler_offsetof(TYPE,MEMBER)
00023: #else
00024: #defineoffsetof(TYPE, MEMBER)((size_t)&((TYPE*)0)–>MEMBER)
00025: #endif
00026: #endif/* KERNEL */
00027:
这句话的目的是为了计算成员member在type数据结构中的偏移量。
根据前一节的内容,我们把地址0强制性转换为type类型的指针,type类型指针中有何成员变量member,那么成员变量member的地址是多少?
假设地址0已经是type类型的指针,那么成员变量member的地址为&(0->member)(不难理解吧)。
前面我们只是假设地址0为type类型的指针,那需要先强制性转换为type类型的指针。那么得到地址0中成员变量member的方式就变为
&((TYPE*)0)–>MEMBER
因为每个结构体在编译时,已知道其大小和各个成员变量大小,就可以简洁方便地计算偏移量。这个偏移量在程序编译时便可确定。
这个地址类型是member的,为了以后的计算,我们需将这个地址转换为无符号长整型(size_t)。
(size_t)&((TYPE*)0)–>MEMBER
3、typeof
从字面意思上理解,typeof就是获取其类型,其含义也正是如此。关键字typeof返回的是表达式的类型,使用上类似于关键字sizeof,但它的返回值是类型,而不是一个大小。下面是一些例子:
char *chptr; // A char pointer
typeof (*chptr) ch; // A char
typeof (ch) *chptr2; // A char pointer
typeof (chptr) chparray[10]; // Ten char pointers
typeof (*chptr) charray[10]; // Ten chars
typeof (ch) charray2[10]; // Ten chars
4、 const typeof( ((type *)0)- >member ) *__mptr
定义一个常量指针__mptr,指针类型是和结构体type中成员变量member数据类型一致。
语句consttypeof(((type*)0)–>member)*__mptr=(ptr);的含义为定义一个临时常量指针__mptr,并把ptr赋值给__mptr。
5、(type *)( (char *)__mptr – offsetof(type,member) )
我们已经得到type类型数据结构(这个结构有个成员变量是member)变量的起始地址,结果是无符号整型的,为了真正能使用这个数据结构,还需最后一步,将其强制性转换为type指针类型。
(type*)((char*)__mptr–offsetof(type,member))
Leave a Reply