Linux内核同时使用C语言和汇编语言来实现。这两种语言需要一定的平衡:C语言编写的代码移植性较好,易于维护,而汇编语言编写的程序则速度较快。一般只有在速度是关键因素或者一些因平台相关特性而产生的特殊要求(例如直接和内存管理硬件进行通讯)时才采用汇编语言。
实际上,即使内核并未采用C++的对象特性,部分内核也可以在g++(GNU的C++编译器)下进行编译。同其他面向对象的编程语言相比较,相对而言C++的开销是较低的,但是对内核开发人员来说,这已经是太多了。
1、gcc特性的使用
Linux内核被设计为必须使用GNU的C编译器gcc来编译,而不是任何一种C编译器都可以使用。内核代码有时要使用gcc特性。
一些gcc特有代码只是简单地使用gcc语言扩展,例如允许在C(不只是C++)中使用inline关键字指示内联函数。也就是说,代码中被调用的函数在每次函数调用时都会被扩充,因而就可以节约实际函数调用的开销。
一般情况下,代码的编写方式比较复杂。因为对于某些类型的输入,gcc能够产生比其他输入效率高的执行代码。从理论上讲,编译器可以优化具有相同功能的两种对等的方法,并且得到相同的结果。因此,代码的编写方式是无关紧要的。但是在实际中,用某种方法编写所产生的代码要比用另外一些方法编写所产生的代码执行速度上快许多。内核开发人员知道怎样才能产生更高效的执行代码,这不断地在他们编写的代码中反映出来。
例如,考虑内核中经常使用的goto语句--为了提高速度,内核中经常大量使用这种一般要避免使用的语句。整个内核的比例大概是每260 行一个goto语句,比例如此高的原因是内核源程序的核心,在这里速度比其他因素都需要优先考虑。
2、内核代码习惯用语
内核代码中使用了一些显著的习惯用语,当通读源代码时,真正重要的不是这些习惯用语本身,而是这种类型的习惯用语的确存在,而且是不断地被使用和发展的。
3、减少#if和#ifdef的使用
现在的Linux内核已经移植到不同的平台上,但是我们还必须解决移植过程中所出现的问题。大部分支持各种不同平台的代码由于必须包含许多预处理代码而已经变得非常不规范。Linux关注的焦点很明显是实现代码在各种CPU上的可移植性,对于这类问题来说,预处理器是一种错误的解决方式。这些杂乱的问题使得代码晦涩难懂。更为糟糕的是,增加对新的平台的支持有可能要求重新遍历这些杂乱分布的低质量代码段(实际上你很难找到这类代码段的全部)。
与现有方式不同的是,Linux一般通过简单函数(或者是宏)调用来抽象出不同平台间的差异。内核的移植可以通过实现适合于相应平台的函数(或宏)来实现。这样不仅使代码的主体简单易懂,而且在移植的过程中还可以比较容易地检测出你没有注意到的内容:如引用未申明函数时会出现链接错误。有时用预处理器来支持不同的体系结构,但这种方式并不常用,而相对于代码风格的变化就更是微不足道了。