写这文处于俩个原因:
(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+b
add(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. 宏定义好难,看上面这个定义,各种括号。。。细心,细心,细心,可惜我是粗心的蓝孩子 = =