文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>《基于Linux的C编程与内核导读》连载(6)

《基于Linux的C编程与内核导读》连载(6)

时间:2009-07-23  来源:叮汀

2.5 linux内核中的C语言

在这里我们并不讲解C语言的各种基础知识,而是针对Linux内核中一些比较特殊的C语言用法做一些简单的说明。

首先,在Linux内核中大量使用了inline函数,从功能上说,inline函数的使用与#define宏定义相似,但更有相对的独立性,也更安全。使用inline函数也有利于程序调试。如果编译时不加优化,则这些inline函数就是普通的、独立的函数。由于inline函数的大量使用,相当一部分的代码从.c文件移入.h文件中。

由于“inline”在C语言中不是保留字(在C++中是保留字),所以为了避免冲突,则在其前后都加上“__”,因而“__inline__”等价于保留字“inline”。同样道理,“__asm__”等价于“asm”。

虽然linux内核代码中使用了大量inline函数,不过这并未消除对宏操作的使用。人们常常会对内核代码中一些宏操作的定义感到迷惑不解,这里有必要做一些解释。先看一个实例,取自fs/proc/kcore.c

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

大家都知道,do-while循环是先执行后判断循环条件,所以,这个定义意味着每当引用这个宏操作时只会执行一次。可是,为什么要这样通过一个do-while循环来定义呢?能不能直接写成下面的形式呢?

#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();

编译这段代码时gcc会失败,并报告语法错误。因为gcc认为if语句在memcpy()以后就结束了,然后却又碰到一个else。读者可能马上会想到在定义中加上大括号,成为这样:

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

可是,上面那段程序还是通不过编译,因为经过预处理就变成这样:

if(addr)

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

else

  do_something_else();

同样,gcc在碰到else前面的“;”时就认为if语句已经结束了,因而后面的else不在if语句中。相比之下,采用do-while的定义在任何情况下都没有问题。

了解了这一点之后,再来看对“空操作”的定义。由于linux内核的代码要考虑各种不同的CPU和不同的系统配置,所以常常需要在一定条件下把某些宏操作定义为空操作。例如在include/asm-i386/system.h中的prepare_to_switch():

#define prepare_to_switch() do{}while(0)

内核在调度一个进程运行,进行切换之际,在有些CPU上需要调用prepare_to_switch()作些准备,而在另一些CPU上就不需要,所以要把它定义为空操作。

    在linux内核中还有许多对C语言的巧妙使用,比如内核采用了一套通用的,可以应用到各种不同数据结构的队列操作。这些我们都将在以后几章的内核导读部分进行详细讲解。
相关阅读 更多 +
排行榜 更多 +
终极街头格斗

终极街头格斗

休闲益智 下载
大炮轰飞机

大炮轰飞机

飞行射击 下载
像素打僵尸

像素打僵尸

飞行射击 下载