linux内核宏如何用作函数?

时间:2014-01-26 09:34:58

标签: c linux macros kernel kernel-module

这个标题可能听起来很愚蠢,但我以前从未见过这样的东西,而且我真的不知道如何描述它:

所以我刚写了第一个内核模块,并使用了一个链表,它使用了linux/list.h头文件。在其中,有这个宏:

400 /**
401  * list_for_each_entry  -       iterate over list of given type
402  * @pos:        the type * to use as a loop cursor.
403  * @head:       the head for your list.
404  * @member:     the name of the list_struct within the struct.
405  */
406 #define list_for_each_entry(pos, head, member)                          \
407         for (pos = list_entry((head)->next, typeof(*pos), member);      \
408              prefetch(pos->member.next), &pos->member != (head);        \
409              pos = list_entry(pos->member.next, typeof(*pos), member))

而且,我这样使用它(假设list_head是列表的头部,list是结构中的list_struct

struct thing *ptr;
list_for_each_entry(ptr, &list_head, list){
        printk(KERN_INFO "contents: %s\n", ptr->something);
}

当我运行dmesg时,列表中的每个项目都有一行...

所以,我的问题是: 这里发生了什么?我之前没有看到使用的宏就好像它们是这样的函数 - 编写一个以这种方式调用的宏的规则是什么?

我只是不明白为什么会这样,或者我如何编写我自己的宏,就像这样。

2 个答案:

答案 0 :(得分:4)

宏只是文本扩展。没有魔法可言。您可以使用gcc -E查看输出。在这种情况下:

#define list_for_each_entry(pos, head, member)                          \
        for (pos = list_entry((head)->next, typeof(*pos), member);      \
             prefetch(pos->member.next), &pos->member != (head);        \
             pos = list_entry(pos->member.next, typeof(*pos), member))

...

struct thing *ptr;
list_for_each_entry(ptr, &list_head, list){
    printk(KERN_INFO "contents: %s\n", ptr->something);
}

扩展为:

struct thing *ptr;
for (ptr = list_entry((&list_head)->next, typeof(*ptr), list);
     prefetch(ptr->list.next), &ptr->list != (&list_head);
     ptr = list_entry(ptr->list.next, typeof(*ptr), list)) {
    printk(KERN_INFO "contents: %s\n", ptr->something);
}

请注意,我没有在那里做任何艰苦的工作,我只是剪切&粘贴代码并通过gcc -E(稍微整理了格式)。

循环(如您所见)在扩展代码中完成。

答案 1 :(得分:2)

要深入了解Linux内核,您需要在C中使用 solid 背景。至少要学习一本教程(如http://www.cprogramming.com/tutorial/c-tutorial.html)并完成它。 Linux专家使用各种毛发构造,既提高效率(每天在数百万台设备上运行数千次的代码),抽象复杂且容易出错的常见结构,也可用于帮助创建与架构无关的代码。宏当然是一个基本的工具,它们是C的一个有点神秘的角落。注意,内核也可以自由地使用所有类型的GCC扩展。