3)宏展开
将对宏的调用展开成相对应的宏定义
关于宏定义还有很多其他的知识点,本文暂不深入展开。
四、如何快速展开复杂的宏定义?
linux内核中通常有很多宏定义,非常的复杂,对于初学者来说,经常会一头雾水,那如何快速理解宏定义呢?
一口君教你一个非常方便的方法,让你直接看透宏定义,我们以上述代码为例:
第一步将要展开的宏先拷贝到c文件中,然后把所有用到的宏定义都拷贝到该文件中;内核中很多的宏都是嵌套的,把嵌套的宏定义都一起拷贝到文件中;此外内核很多的宏会由条件编译决定,从而导致有多种定义方式,如果不确定,就把条件编译一起拷贝过来,
如该例所示,MAX_NUMNODES 就被嵌套了多级,最终宏CONFIG_NODES_SHIFT在内核中没有检索到,所以该宏没有定义。
文件如下:123.c
1
2
3 #ifdef CONFIG_NODES_SHIFT
4 #define NODES_SHIFT CONFIG_NODES_SHIFT
5 #else
6 #define NODES_SHIFT 0
7 #endif
8
9
10
11 #define MAX_NUMNODES (1 << NODES_SHIFT)
12
13
14
15
16 #if MAX_NUMNODES > 1
17 #define for_each_node_state(__node, __state)
18 for_each_node_mask((__node), node_states[__state])
19 #else
20 #define for_each_node_state(node, __state)
21 for ( (node) = 0; (node) == 0; (node) = 1)
22 #endif
23
24
25
26
27 #define for_each_online_node(node) for_each_node_state(node, N_ONLINE)
28
29
30 static int __build_all_zonelists(void *data)
31 {
32 int nid;
33 int cpu;
34 pg_data_t *self = data;
35
36
37
38 for_each_online_node(nid) {
39 pg_data_t *pgdat = NODE_DATA(nid);
40
41 build_zonelists(pgdat);
42 build_zonelist_cache(pgdat);
43 }
44 }
第二步
使用以下命令,展开宏定义,
gcc -E
-E的含义是,编译预处理该文件,但是不去生成汇编代码,只把文件中的宏定义以及包含的头文件替代,并不会去检查语法正确与否。
结果如下:
peng@ubuntu:~/test$ gcc 123.c -E
# 1 "123.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "123.c"
# 28 "123.c"
static int __build_all_zonelists(void *data)
{
int nid;
int cpu;
pg_data_t *self = data;
for ( (nid) = 0; (nid) == 0; (nid) = 1) {
pg_data_t *pgdat = NODE_DATA(nid);
build_zonelists(pgdat);
build_zonelist_cache(pgdat);
}
}
由结果可知,nid是被赋值为0的。
五、练习
我们来做一个练习,展开一下内核的waite_event()这个宏
拷贝用到所有宏定义到c文件中。
wait.c
1
2 #define ___wait_event(wq, condition, state, exclusive, ret, cmd)
3 ({
4 __label__ __out;
5 wait_queue_t __wait;
6 long __ret = ret;
7
8 INIT_LIST_HEAD(&__wait.task_list);
9 if (exclusive)
10 __wait.flags = WQ_FLAG_EXCLUSIVE;
11 else
12 {
13 code
14 __wait.flags = 0;
15
16 for (;;) {
17 long __int = prepare_to_wait_event(&wq, &__wait, state);
18
19 if (condition)
20 break;
21
22 if (___wait_is_interruptible(state) && __int) {
23 __ret = __int;
24 if (exclusive) {
25 abort_exclusive_wait(&wq, &__wait,
26 state, NULL);
27 goto __out;
28 }
29 break;
30 }
31
32 cmd;
33 }
34 finish_wait(&wq, &__wait);
35 __out: __ret;
36 })
37 }
38
39
40
41
42 #define TASK_UNINTERRUPTIBLE 2
43
44
45 #define __wait_event(wq, condition)
46 (void)___wait_event(wq, condition, TASK_UNINTERRUPTIBLE, 0, 0,
47 schedule())
48
49