Chinaunix首页 | 论坛 | 博客
  • 博客访问: 73627
  • 博文数量: 9
  • 博客积分: 176
  • 博客等级: 入伍新兵
  • 技术积分: 142
  • 用 户 组: 普通用户
  • 注册时间: 2010-10-29 09:52
文章分类

全部博文(9)

文章存档

2015年(3)

2012年(6)

我的朋友

分类: LINUX

2015-05-22 23:22:18

不想从AT&T汇编语言以及系统启动和加载的过程来写了,这些东西都比较好理解,就直接从内核的常见数据结构和宏定义来写吧

1、链表:确切的说应该是双向链表,定义位置根据版本不同略有不同,不过内容都是一样的,定义如下

  1. struct list_head {
  2.     struct list_head *next, *prev;
  3. };
       这个链表没有任何特别之处,但是用的方法比较特别,内核管理的很多数据结构中都定义了这个链表类型的成员。根据这个特殊的成员,内核就可以找到包含该成员的容器的指针,这个就要用到一个特殊的宏定义了,下面介绍第二个非常重要的宏定义list_entry。

2、list_entry宏定义如下

  1. /**
  2.  * list_entry - get the struct for this entry
  3.  * @ptr:    the &struct list_head pointer.
  4.  * @type:    the type of the struct this is embedded in.
  5.  * @member:    the name of the list_head within the struct.
  6.  */
  7. #define list_entry(ptr, type, member) \
  8.     container_of(ptr, type, member)
        list_entry可以通过成员指针及成员名称获取容器类型的指针。从代码注释可以看出,list_entry宏定义用于获取包含ptr且变量名称为member的容器type的指针,这个宏定义也很简单,只是引用了container_of宏定义。

3、container_of宏定义如下
  1. /**
  2.  * container_of - cast a member of a structure out to the containing structure
  3.  * @ptr: the pointer to the member.
  4.  * @type: the type of the container struct this is embedded in.
  5.  * @member: the name of the member within the struct.
  6.  *
  7.  */
  8. #define container_of(ptr, type, member) ({ \
  9.     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
  10.     (type *)( (char *)__mptr - offsetof(type,member) );})
从定义可以看出,首先定义了一个与member类型一样的临时指针__mptr,并给这个临时指针赋值为ptr,然后再用__mptr减去memeber在type容器中的偏移量即可。那么offsetof这个宏又是如何定义的呢?

4、offsetof宏定义如下

  1. #ifdef __compiler_offsetof
  2. #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
  3. #else
  4. #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
  5. #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类型。

先写这么多,操作系统中对宏的应用是非常多的,也是非常巧妙的,看懂内核源代码,这是基本知识必不可少。

阅读(890) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~