6 操作系统开发中的困难
现在市面上众多的C编译器都是以开发Windows或Linux上的应用程序为前提而设计的,几乎从来没有人想过要用它们来开发其他的软件,比如自己的操作系统。笔者所提供的编译器,也是以Windows版的gcc为基础稍加改造而做成的,与gcc几乎没什么不同。或许也有为开发操作系统而设计的C编译器,不过就算有,恐怕也只有开发操作系统的公司才会买,所以当然会很贵。这次我们用不了这么高价的软件。
因为这些原因,我们只能靠开发应用程序用的C编译器想方设法编写出一个操作系统来。这实际上是在硬来,所以当中就会有很多不方便的地方。
就比如说printf(“hello\n”);吧,这个函数总是出现在C语言教科书的第一章,但我们现在就连它也无法使用。为什么呢?因为printf这个函数是以操作系统提供的功能为前提编写的,而我们最开始的操作系统可是什么功能都没有。因此,如果我们硬要执行这个函数的话,CPU会发生一般保护性异常,直接罢工。刚开始的时候不仅是printf,几乎所有的函数都无法使用。
关于这次开发语言的选择,如果非要说出个所以然的话,其实也是因为C语言还算是很少依赖操作系统功能的语言,基本上只要不用函数就可以了。如果用C++的话,像new/delete这种基本而重要的运算符都不能用了,另外对于类的做法也会有很多要求,这样就无法发挥C++语言的优势了。当然,为了使用这些函数去开发操作系统,只要我们想办法,还是能够克服种种困难的。但是如果做到这个份上,我们不禁会想,到底是在用C++做操作系统呢,还是在为了C++而做操作系统呢。对别的语言而言这个问题会更加突出,所以这次还是决定使用C语言,希望大家予以理解。
顺便插一句,在开发操作系统时不会受到限制的语言大概就只有汇编语言了。还是汇编语言最厉害(笑)。但是如果本书仅用汇编来编写操作系统的话,恐怕没几个人会看,所以就算是做事管前不顾后的笔者也不得不想想后果。
另外,在开发操作系统时,需要用到CPU上的许多控制操作系统的寄存器。一般的C编译器都是用于开发应用程序的,所以根本没有任何操作这些寄存器的命令。另外,C编译器还具有非常优秀的自动优化功能,但有时候这反而会给我们带来麻烦。
归根到底,为了克服以上这些困难,有些没法用C语言来编写的部分,我们就只好用汇编语言来写了。这个时候,我们就必须要知道C编译器到底是怎样把程序编译成机器语言的。如果不能够与C编译器保持一致的话,就不能将汇编语言编写的部分与C语言编写的部分很好地衔接起来。这可是在编写普通的C语言程序时所体会不到哦!不过相比之下,今后的麻烦可比这种好处多得多啊(苦笑)。
同样,如果用C++来编写操作系统,也必须知道C++是如何把程序编译成机器语言的。当然,C++比C功能更多更强,编译规则也更复杂,所以解释起来也更麻烦,我们选用C语言也有这一层理由。总之,如果不理解自己所使用的语言是如何进行编译的,就没法用这种语言来编写操作系统。
书店里有不少C语言、C++的书,当然也还有Delphi、Java等其他各种编程语言的书,但这么多书里没有一本提到过“这些源代码编译过后生成的机器语言到底是什么样的”。不仅如此,虽然我们是在通过程序向CPU发指令的,但连CPU的基本结构都没有人肯给我们讲一讲。作为一个研究操作系统的人,真觉得心里不是滋味。为了弥补这一空缺,我们这本书就从这些基础讲起(但也仅限于此次开发操作系统所必备的基础知识)。
我们具备了这样的知识以后,说不定还会改变对程序设计的看法。以前也许只想着怎么写出漂亮的源代码来,以后也许就会更注重编译出来的是怎样的机器语言。源代码写得再漂亮,如果不能编译成自己希望的机器语言,不能正常运行的话,也是毫无意义的。反过来说,即便源代码写得难看点儿,即便只有特定的C编译器才能编译,但只要能够得到自己想要的机器语言就没有问题了。虽然不至于说“只要编译出了想要的机器语言,源代码就成了一张废纸”,但从某种意义上说还真就是这样。
对于开发操作系统的人而言,源程序无非是用来得到机器语言的“手段”,而不是目的。浪费太多时间在手段上就是本末倒置了。
对了,还有一点或许会有人担心,所以在这里事先说明一下:虽然操作系统是用C语言和汇编语言编写的,但并不是用C++编写的应用程序就无法在这个操作系统上运行。编写应用程序所用的语言,与开发操作系统所使用的语言是没有任何关系的,大家大可不必担心。