不想从AT&T汇编语言以及系统启动和加载的过程来写了,这些东西都比较好理解,就直接从内核的常见数据结构和宏定义来写吧
1、链表:确切的说应该是双向链表,定义位置根据版本不同略有不同,不过内容都是一样的
,定义如下
-
struct list_head {
-
struct list_head *next, *prev;
-
};
这个链表没有任何特别之处,但是用的方法比较特别,内核管理的很多数据结构中都定义了这个链表类型的成员。根据这个特殊的成员,内核就可以找到包含该成员的容器的指针,这个就要用到一个特殊的宏定义了,下面介绍第二个非常重要的宏定义list_entry。
2、list_entry宏定义如下
-
/**
-
* list_entry - get the struct for this entry
-
* @ptr: the &struct list_head pointer.
-
* @type: the type of the struct this is embedded in.
-
* @member: the name of the list_head within the struct.
-
*/
-
#define list_entry(ptr, type, member) \
-
container_of(ptr, type, member)
list_entry可以通过成员指针及成员名称获取容器类型的指针。从代码注释可以看出,list_entry宏定义用于获取包含ptr且变量名称为member的容器type的指针,这个宏定义也很简单,只是引用了container_of宏定义。
3、container_of宏定义如下
-
/**
-
* container_of - cast a member of a structure out to the containing structure
-
* @ptr: the pointer to the member.
-
* @type: the type of the container struct this is embedded in.
-
* @member: the name of the member within the struct.
-
*
-
*/
-
#define container_of(ptr, type, member) ({ \
-
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
-
(type *)( (char *)__mptr - offsetof(type,member) );})
从定义可以看出,首先定义了一个与member类型一样的临时指针__mptr,并给这个临时指针赋值为ptr,然后再用__mptr减去memeber在type容器中的偏移量即可。那么offsetof这个宏又是如何定义的呢?
4、offsetof宏定义如下
-
#ifdef __compiler_offsetof
-
#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
-
#else
-
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
-
#endif
从定义看这个宏依赖编译器,如果编译器内建了__compiler_offsetof(TYPE,MEMBER)的实现,就使用编译器的实现,反之则采用((size_t) &((TYPE *)0)->MEMBER)来实现,从后面这个((size_t) &((TYPE *)0)->MEMBER)来看就很好理解了。下面根据运算优先级依次解释一下就好理解了。
TYPE * 表示TYPE类型的指针。
(TYPE *)0 则表示这个指针的值是零,比如TYPE * pTYPE = (TYPE *)0;就是这个道理。
((TYPE *)0)->MEMBER 表示起始地址为0的TYPE容器中的MEMBER成员
&
((TYPE *)0)->MEMBER 则表示要取MEMBER成员的地址,如果基地址为0,则MEMBER的地址就可以看成是偏移量offset了
(size_t) &((TYPE *)0)->MEMBER则只是做了一个类型转换,将指针转化为size_t类型。
先写这么多,操作系统中对宏的应用是非常多的,也是非常巧妙的,看懂内核源代码,这是基本知识必不可少。
阅读(906) | 评论(0) | 转发(1) |