寫操作系統只能用彙編和 C 語言嗎?

在看《現代操作系統》的時候,作者說寫操作系統只能用彙編、C以及少數部分可以用C++,而不能用Java、Python 、Pascal。Java和Python 不能寫我想的通,但是Pascal也是能像C語言那樣直接編譯成二進位文件的啊,而且也不缺少指針這些玩意,出現的也比C語言早,為什麼就不能寫操作系統了?Pascal比C差在哪了?注意:這裡說的操作系統不包括操作系統周邊的一些程序,專指內核或者比內核稍大一點的部分(自己感覺下啦)。


理論上說,大部分語言都可以用來寫操作系統內核

但是為什麼大部分操作系統內核都只用C語言來寫?因為目前所有的語言的開發環境里,C語言能做到編譯成不依賴操作系統的形式二進位代碼,C語言的各種脫離系統的庫最豐富,最完整,C語言用來開發操作系統的工具最多。

舉個例子:

如果內核中希望使用printf這個函數,那麼內核就必須自己實現printf,而不是依賴標準庫,因為標準庫是要依賴操作系統來完成真正的printf操作。而這種庫,C語言版本的最容易找到,其它語言要麼沒有,要麼很難用。

題主有興趣可以看Linux源碼、網上泄露的Windows源碼、ReactOS源碼、以及各種嵌入式平台的源碼(uC/OS,ThreadX,VxWorks等),這些源碼的一個特點就是它們自身都實現了大部分標準庫的函數。

所以語言本身是什麼不重要,重要的是語言運行所依賴的東西。

如果有人使用Pascal實現了Pascal標準庫里的大部分功能,並且都不依賴於操作系統,那麼用這個環境就可以用來開發Pascal寫的操作系統。

有人會說解釋型的語言肯定不合適,但是,實際上如果有人能移植一套不依賴操作系統的Java虛擬機,那麼虛擬機之上完全可以開發一套以Java語言開發的操作系統。解釋型的語言難點在於解釋器,但如果解釋器不依賴操作系統,那麼語言本身也可以做到不依賴。

回到問題,編程語言只是工具,不同語言之間確實在做事情上有差異,但如果付出一些代價(成本),那麼工具的限制因素就會降低。

用機床可以做零件,但用斧頭、鎚子、電鑽、刀具就不能做了嗎?只不過很麻煩而已。

商用操作系統用C語言開發是因為工具齊全開發成本低,僅此而已。

給個鏈接,JNode,一個用Java寫的操作系統:

JNode

這個世界上有很多閑人,他們一直在做著各種稀奇古怪的事情,就包括用各種語言開發操作系統。

看到題主有一點不明白,那麼我再補充一下:

一個語言的第一個版本肯定是用別的語言寫的,但以後的版本就不一定了。這像是一個先有雞還是先有蛋的問題,但實際不是。舉個例子吧:C語言的最早的編譯器肯定不是C寫的,但用最早的編譯器環境里的C語言是可以做出更複雜的編譯器的,更複雜的編譯器再做出支持更複雜語法的C,不停的迭代就可以了。迭代不僅僅可以是C語言,也可以是其它語言,就這樣的。


System 7之前的老Mac OS很大一部分就是pascal寫的,雖然老Mac OS根本不算是現代意義的OS。


編寫操作系統內核並不是只能用彙編跟C,C++的,非常早期的Mac操作系統,還有一個Apple Lisa機子的操作系統是題主所提到的Pascal所編寫的。對,兩個都是蘋果的。

那麼為啥彙編,C/C++在操作系統裡面那麼流行呢?

首先由彙編說起。現在常見的操作系統是有少量彙編代碼的。為什麼要彙編呢?因為boot的時候會有一些切換處理器模式之類雜七雜八的指令,用彙編干這種活簡單粗暴,代碼量也就100行,寫好了就不需要動,不需要維護(除非有處理器架構有大的變化)。用彙編就圖個省事。在其他大部分地方就大都用C/C++編寫了

C在操作系統中流行跟1970年代Unix出現有關。C語言最初是伴隨著Unix出現的,最初的Unix是主要由彙編編寫,部分應用程序使用了B語言(早期的一門高級語言)。為了編寫方便,Unix開發人員決定改造B語言並用其來開發Unix後續的版本,丹尼斯里奇把B語言改造成了C語言。

現在常見的操作系統內核主要有Linux, Unix, Darwin(Mac OSX的內核)以及NT(windows的內核)。Linux, Unix, Darwin本質上都是unix/類unix操作系統,用c語言編寫是非常自然的事情。而NT內核則是Dave Culter帶領團隊開發的,很巧,他也選了c語言作為開發語言。造成了現在常用的操作系統內核基本上都是由c語言編寫的,也給一些人一種只能用C語言寫操作系統的印象。

另外一方面,C語言有其在開發操作系統上的優勢。操作系統一個很重要的功能是進行內存管理,Java, Python之類的不能直接操縱內存的語言要做內存管理是很困難的事情。而且內聯彙編什麼的在C語言當中太方便了,Java, Python開發操作系統好像用挖掘機穿針似的。C++能寫操作系統內核,L4微內核的一些版本是C++實現的。至於Pascal,個人覺得應該跟C差別不大。注意到Pascal是強類型的,可能會略微不方便吧,但是個人覺得還是歷史原因居多。

對於 @北極 提及到的JNode,個人去其Github上稍微看了它的代碼,內存管理部分是彙編寫的,然後相當一部分代碼是需要使用L2編譯器編譯的,這個編譯器出來的是X86原生代碼,而非JVM的bytecode。覺得不是出於科研的目的的話硬是這樣搞的確挺蛋疼。

對於當前的操作系統開發,特別是商業操作系統的開發,設計人員會遵循很多的慣例,使用彙編+C語言是其中一個。遵從這些經過無數次驗證的慣例至少不會自己給自己找麻煩,也算是一種捷徑吧。但是這些慣例總會過時的,也總需要有人走出新的道路。之前看了微軟的一篇Paper,研究人員把c#改成一門叫Sing#的語言開發了一個操作系統,使用Sing#這門語言類型安全,內存安全的特性來提高操作系統的安全性,也使得進程能夠在Ring0,同一個內存地址空間當中互相隔離。非常創新的一種做法,但是也顛覆了整個軟體棧,所有應用、驅動代碼要重寫,沒有啥兼容性,微軟曾經想把它實用化,可惜失敗告終。或許對以後的操作系統設計有著一定影響吧。

好吧。。離題了那麼多。。簡單回答題主的問題吧,」寫操作系統只能用彙編、C以及少數部分可以用C++「表述是錯誤的,Pascal能寫操作系統內核。


準確的說只能用彙編寫,而c可以做到和彙編一一對應而已。你以為人家在寫c,其實人家腦袋裡面想的是彙編,只不過c敲起來快一點而已。

在直接操作硬體這一級,必須要能夠完全控制生成的彙編代碼是啥,比如要確保你操作的是寄存器而不是內存緩存,確保排時序的時候不會有時鐘周期被優化掉了,或者莫名其妙多了一大堆內存操作。越高層的抽象,越難保證底層的實現是按預期工作的。

而如果剔除掉那些語言提供的高級功能,你就發現其實你在寫c了。

其實這個層面的東西,大多是硬體決定的,軟體能夠騰挪的空間很小。

就好象lisp machine,它的操作系統當然就該用lisp來寫,sun曾經計劃中的,直接運行jvm opcode的cpu,就是專門給java定做的,其他語言沒得搶,是一個道理。

unix hater book講過這個觀點,大意就是,c能夠涵蓋所有功能的這個體系的cpu贏了,unix贏了。其他更好,更複雜,硬體能夠支持更多語言特性的cpu輸了,cpu進入了拼性能而不是拼功能的時代…


可參閱這本書


一般來說,你必須用彙編語言製作引導部分(當然,這部分理論上肯定能通過高級語言編譯出來,但是不是很方便),然後你需要用一種語言編寫內核的主要部分,這個選擇就很多了,C/C++/D等等Native語言都可以,不過一般要用特別的,不同於一般應用層編程的編譯或鏈接參數,這上面說的是可行性,就是說你用C/C++/D肯定能寫出來,一般來說,為了寫出來的內核比較好,你還需要一些其他要求,比方:

  1. 生成代碼尺寸可控,這個C比其他的都強,C++一般來說不適合寫內核就是這個原因
  2. 延遲可控,這是就GC而言的,就算你寫的不是實時操作系統,做某件事的時候觸發GC也是很恐怖的,當然了,要有GC得有Runtime,這事本身是個麻煩,但不是辦不到的
  3. 精確控制內存使用和內存布局,因為你操作系統就是管這個的,這就是說,帶GC的語言一般來說不適合寫內核,或者說內核核心的部分,如果你要用這種語言寫內核,那麼在很多地方,你可能需要閹割掉GC改用手工管理內存(如D)。


其實,如果寫unikernel的話,用高級語言完全OK啊。一個不錯的例子就是OCaml/MirageOS


基本是這樣。

原因是彙編和C語言是兼具

1. 最接近計算機體系結構

2.適合人類編程

這兩個特點。

彙編更接近1,C語言更接近2。

可以讀讀《操作系統設計與實現》(第三版,Tanenbaum,電子工業出版社),講了許多操作系統的設計與實現的細節。


哪兒這麼多廢話。。不是。Mac OS 就是 Pascal 寫的。


不是,你完全可以不用彙編,但是你用的語言一定要可以操作寄存器,編譯出所有指令,而這個語言在現在只有彙編,但是彙編效率低,所以大部分開發用高級語言,我不知道Pascal,但是你在用C的時候只能用與操作系統無關的庫函數,Print就不能用,max就能用(C里有max么,我不知道- -!)


操作系統我是沒寫過的,但是我用C語言和彙編語言給C51單片機寫了很多的程序, 談點自己的看法。

使用何種語言寫操作系統,很大一部分原因是受到目標平台硬體的影響,或者更準確地說,是CPU的影響。彙編語言其實和機器語言之間幾乎可以畫上等號了,所有指令(不包括偽指令)都與CPU的指令集對應(所以很多時候開發彙編語言的編譯器是相對簡單的工作)。而C語言應該是最接近彙編的語言,可能沒有之一,學過彙編之後再去學習C,會發現很多C的數據類型和結構等,例如數組,指針等,都能夠在彙編中找到對應的定址方法。另外,C語言比較容易書寫,例如一個循環或者過程,你在彙編中要留意使用到了哪些寄存器、堆棧等,要保護現場,之後還要恢復現場,保持堆棧平衡等等,稍不留神就會帶來問題。但是用C語言一個for循環,或者一個函數,能省去彙編中很多枯燥麻煩而又容易出錯的工作。如果有興趣,可以試著反編譯一下現代C編譯器(例如gcc)產生的目標文件,會發現其生成的代碼和手工寫彙編的代碼具有相當的指令條數和指令周期,在打開某些高級選項時,還能利用CPU較新的指令,例如條件傳遞(cmov等),提升程序的執行效率,因此用C語言開發一個操作系統是很自然的事情。

但是說只能用C語言和彙編開發操作系統肯定是不正確的,竊以為,所有能夠生成對應硬體平台的CPU指令集的語言,都是可以用來開發操作系統的,但是還是會涉及到兼容性、難易程度等多方面的問題,而且目前的幾個操作系統,如UNIX,Windows、Linux等都是用C語言開發的,所以自然而然地這個就成了業界「潛規則」了,而且在拋開演算法和數據結構的差異下,C語言的速度幾乎是最快的了,在某種程度上,甚至和彙編不相上下,雖然C的語法容易帶來quick dirty的效果,但是對於精通C語言的人來說,這正是C的美妙之處。

據說在Vista的開發中就用到了部分C#,不知是真是假,反正剛推出的時候用戶體驗很不好,在看李開複寫的書中,似乎有提到是比爾蓋茨一開始把目標定得太高?


不是的。

用機器語言也可以。

任何可以精確控制CPU的語言都可以。


只要那種語言可以在沒有Runtime的情況下也能跑,用它寫操作系統肯定沒問題。

用Pascal當然可以,用Rust也可以。


事實上

只要能操作 binary

就可以寫 OS

只是用 python 寫確實有點怪怪的


Redox - Your Next(Gen) OS

自己看一下吧


我記得,Apple Lisa的系統的大部分代碼是用一個特殊版本的Pascal寫的


推薦閱讀:

不同的IDE在編譯代碼時是否存在區別?如果有,那請問區別是什麼?
C語言為什麼要有 main 函數?具體作用是什麼?
如果scanf的格式指示符是%f,賦給一個double型的變數,在內存層面上會發生什麼?
指針可以修改const修飾的變數么?
int (*pf)(1024)為什麼是函數調用?

TAG:操作系統 | C編程語言 | 彙編語言 | Pascal |