Linux内核工程导论——内核为何使用C语言

C与C++的对比无数人说过,都说C效率高,但很多人做过实验如果C++不使用RTTI,C++的效率也不会低太多(25%左右)。还有人说C++强大的STL,但是对效率讲究点的话那个真的不能用,具体我后面说。一般大部分人的心态是,学C++出身的,就经常吐槽linux的C代码乱的一塌糊涂,各种敏捷,面向对象原则,代码不如C++精简,连个STL或者boost都用不上,等软件工程相关问题都是被他们吐槽的重灾区,这些人肯定没有给内核贡献过代码。做嵌入式一直用C的,接触内核后的反应是:啊,内核真大,啊,内核真难懂,是一种敬畏,与吐槽可不一样。

面向对象的实现方法不止C++一种,C也可以做到,只是不如C++那样浑然天成。重要的是,C做的面向对象,由于封装性差,你看一个结构体就会发现里面咋啥都有,乱七八糟。而用C++封装的结构体,可以设计的很潇洒。vector可比list* people更能传递更多的信息。利用C++的封装特性带来的好处是视觉上的显而易见,基本上不需要考虑内存布局,但C的结构体到处都是内存上的考虑,例如通过结构体成员找到结构体本身的container_of,在结构体最后添加一个0长度的数组,在结构体的开头添加一个list*节点。诈一看,C++也能做到,这不是废话吗?C的所有关键字C++都是完全支持的。问题是,这并不是面向对象的思路,有一种编程思路叫做ODP,面向数据编程,说C比C++高效,更多的并不一定是说C++本身效率低,而是其所代表的面向对象思路效率低。我举个例子:

struct A{

int a;

int b;

  }

vector  aList;

我们队这个aList的a变量进行遍历,比起下面这个写法:

struct A{

vector a;

vector b;

}aList;

一定是下面这个效率高。为什么呢?原因在缓存。所有的计算机系统都有缓存行,第二种写法被调入缓存的全部是a,而第一种,还调入了b,遍历起来相当于第一种比第二种缓存减小了一半。自断一臂。这就是ODP比OOP高效的地方。而当你不选用OOP时,C++比C的最大优势就荡然无存。

有的人说C++的STL和boost库。这个就不讲究了。这种库都是通用的,一般大型的企业用到后期对效率开始纠结的时候,通用的东西永远,是永远不可能在所有应用情况是最优的选择。包括内存算法,包括进程调度,包括网络应用,简单说要针对不同应用调整参数,例如TCP在samba时要关闭nagle才能提高效率,但有的应用nagle则是提高效率的利器。内核这种底层的东西,使用这种程度上通用的东西确实不讲究了。最通用的数据结构应该是list了,在数据组织上也是非常的轻量,甚至在组织不同的应用时还有hlist和llist等变体。这种变体可不是C++的再封装所能满足的。

C++最骄傲的:封装、不怎么内存关心、虚函数、继承。虚函数说真的确实是机制上的效率问题,一用它就得多一个虚函数表,这还不是小事,函数调用跳转带来的缓存的刷新可真不是小事。只要你用了虚函数,说不定哪个地方就给你刷一下缓存,这可要命了。在实现一个算法的时候都是小心翼翼的关心每个函数调用是不是坑。至于继承,这个说真的,任何一个写了很久C++代码的人都有一个体会:除非你是做应用软件,否则真没那么多变体。在内核开发来说,基本就是鸡肋,可能会有几个地方可以用到这个特性,但这完全不构成因此而选择这门更复杂语言的理由。不关心内存的潇洒的写代码,如果你是做大型商用平台式应用软件的恐怕都不会不考虑内核布局,甚至是有的代码还要刻意的挑出来用C或者汇编重写。这种优化技能存在已久。

我们在使用C++的时候有很多设计模式,有很多编程技巧。他们带来的效果大部分是架构清晰,代码量变少,易于修改。然而在调优一份嵌入式代码的时候,或者一个系统的使用的时候,那点代码量的差距在使用上根本不是个事。最多多出1M的代码?即使不压缩都不会有这么多,压缩后就基本看不出来了。所以,你只能嫌弃他写的代码难看。但是我推荐你用source insight跟一下代码,或者是你有别的工具。C的代码确实多一些,但是跟代码的时候的痛快是C++你要到处去找到底是哪个虚函数还是子类在起作用。毕竟人家是运行时才确定的,而你看代码的时候是静态的。这有一个本质的原因:C可以看静态代码得出全部意图,但C++不能或者很难。而,内核的开发者(其实用过的都知道,大部分工作都是跟代码的人)真正要动手写的代码基本不存在。所以,对内核来说,即使是深度使用内核的人大部分也是使用者,而并非开发者,如此情况,追求敏捷的意义又有多大呢?

我也曾诟病内核的很多C代码写的那简直叫没有人性。比如电梯算法的框架代码,你得看到头发都白了才能大概体会作者的意图。然而,那又怎样?即使我很容易看懂了,我会去修改他吗?他提供了很多的参数,我所需要的,参数调整而已。修改和维护自有作者自己在维护。可能大家说我不知道上进,那就是没有实际做过内核开发的人了,当你告诉上司你修改了很多电梯的框架时,你问问公司的领导敢用吗?做到这个程度的产品基本是嵌入式产品,嵌入式产品的软件一发布基本就不容易更新软件了。这种冒险如果修改参数可以完成,怎么会有决策者采用呢?技术在产品面前,是要服务于产品的。

我也是C++的拥护者,甚至是狂热者,日常的软件,大部分的公司产品,哪怕是互联网产品,我都会选择C++或者java,而绝对不会选择C。我怕团队离开一个人,我怕项目的增量能力不足。然而,在深入内核之后,我也会选择C,面向对象确实是编程的一大进步,那你怎么不去问问数据库大行其道的为啥不是实体联系模式,而是关系模式?我们可以采用新技术,我也承认新技术带来的生产力革命,但是我们不应该迷信新技术。

你可能感兴趣的:(linux,linux内核原理)