关于Linux内核源代码情景分析的点点滴滴

来源:互联网 发布:安卓系统源码网盘下载 编辑:程序博客网 时间:2024/05/22 00:07

写这文处于俩个原因:
(1) 备份,以便日后
(2) 分享
许多东西都是在这本书上看到的,也算是安利吧。

1. 宏定义好难

书上给的例子是:

#define DUMP_WRITE(addr, nr) do{ memcpy(bufp, addr, nr); bufp += nr;} while(0)

咋一看为什么不写成

#define DUMP_WRITE(addr, nr) memcpy(bufp, addr, nr); bufp += nr;

书上给的例子是

if (addr)     DUMP_WRITE(addr, nr);else    do_something_else();

如果是下面的话,就是:

if (addr)    memcpy(bufp, addr, nr); bufp += nr;else    do_something_else();

编译不过。

那么加个中括号呢

#define DUMP_WRIET(addr, nr) { memcpy(bufp, addr, nr); bufp += nr; }

那更不行了

if (addr)    { memcpy(bufp, addr, nr); bufp += nr; };else    do_something_else();

毕竟宏定义可以理解为直接替换。想想下面经典的例子就是了:

#define add(a, b) a+badd(1, 2) * 3 等价于 1 + 2 * 3

所以说写一个到处都能使用的宏定义代码,好难。共勉。

2. 链表的那些事

标准的链表结构如下(双向的)

typedef struct foo{    struct foo *prev;    struct foo *next;}foo;

虽然声明这样的结构不费劲,但是这种结构只能用于foo类型中,对于新的类型bar的话,则必须再次声明(结构还是相类似!!)说到这里,我是想到了模板template。但是这个是C++才引入的。而linux里面的做法是什么呢?
linux里面的做法是这样的:
它定义一个
数据结构:

struct list_head {    struct list_head *next, *prev;}

对于foo类型:

typedef struct foo {    struct list_head list;    ...}

至于怎么知道foo的next呢?毕竟我们所知道的是foo1 foo1.list 以及foo1.list.next 也就是foo2.list, 怎么反推到foo2呢? 看以下程序

 1|#include "stdio.h" 2| 3|struct list_head { 4|    struct list_head *next; 5|};                                        6|typedef struct foo { 7|    struct list_head list; 8|    int num; 9|} foo;10|11|int main() {12|    foo f1, f2;13|    f1.num = 1;14|    f2.num = 2;15|    f1.list.next = &(f2.list);16|    foo *pf2 = (foo *)f1.list.next;17|    int answer = pf2->num;18|    printf("f1: %d, f2: %d", f1.num, answer);19|20|    return 0;21|}                       

首先由于在foo数据结构里面list_head是首位元素,所以list_head的地址就是foo的地址。但是:这个代码是我自己写的,连我自己都不敢用 = =(毕竟涉世不深,行差踏错。。。)只是提供一下思路(亲测有效,不过不知道这么写是否能够到处都能禁得住使用,求赐教)。

书上提供的方法是这个:

#define list_entry(ptr, type, member) \    ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))

注意括号,使用例子如下:

 1|#include "stdio.h"                                                                     2| 3|struct list_head { 4|    struct list_head *next; 5|}; 6|typedef struct foo { 7|    struct list_head list; 8|    int num; 9|} foo;10|11|#define list_entry(ptr, type, member) \12|    ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))13|14|int main() {15|    foo f1, f2;16|    f1.num = 1;17|    f2.num = 2;18|    f1.list.next = &(f2.list);19|    foo *pf2 = list_entry(f1.list.next, foo, list);20|    int answer = pf2->num;21|    printf("f1: %d, f2: %d", f1.num, answer);22|23|    return 0;24|}

首先得理解list_entry 做了什么事。
他做的事目的是:从list_head* next指针中获取其对应的foo指针。
适用性:list_head 不需要是foo结构的首个元素。
原因:因为它将list_head* next指针地址 减去 list_head*指针相对于foo的地址 = foo指针地址(P.S. 在foo结构中,foo指针地址 <= list_head指针地址)

这也是 (unsigned long)(&((type *)0)->member)的含义,取 member 相对于 type 结构的相对位置。

看起来是不是跟我的差不多,嘻嘻。不过确实在适用性方面增加不少。共勉。
P.S. 宏定义好难,看上面这个定义,各种括号。。。细心,细心,细心,可惜我是粗心的蓝孩子 = =

0 0
原创粉丝点击