程序員需要了解的硬核知識(shí)之操作系統(tǒng)和應(yīng)用
利用計(jì)算機(jī)運(yùn)行程序大部分都是為了提高處理效率。例如,Microsoft Word 這樣的文字處理軟件,是用來提高文本文件處理效率的程序,Microsoft Excel 等表格計(jì)算軟件,是用來提高賬本處理效率的程序。這種為了提高特定處理效率的程序統(tǒng)稱為 應(yīng)用
程序員的工作就是編寫各種各樣的應(yīng)用來提高工作效率,程序員一般不編寫操作系統(tǒng),但是程序員編寫的應(yīng)用離不開操作系統(tǒng),此篇文章我們就針對(duì) Windows 操作系統(tǒng)來說明一下操作系統(tǒng)和應(yīng)用之間的關(guān)系。
操作系統(tǒng)功能的歷史
操作系統(tǒng)
其實(shí)也是一種軟件,任何新事物的出現(xiàn)肯定都有它的歷史背景,那么操作系統(tǒng)也不是憑空出現(xiàn)的,肯定有它的歷史背景。
在計(jì)算機(jī)尚不存在操作系統(tǒng)的年代,完全沒有任何程序,人們通過各種按鈕
來控制計(jì)算機(jī),這一過程非常麻煩。于是,有人開發(fā)出了僅具有加載和運(yùn)行功能的監(jiān)控程序
,這就是操作系統(tǒng)的原型。通過事先啟動(dòng)監(jiān)控程序,程序員可以根據(jù)需要將各種程序加載到內(nèi)存中運(yùn)行。雖然仍舊比較麻煩,但比起在沒有任何程序的狀態(tài)下進(jìn)行開發(fā),工作量得到了很大的緩解。
隨著時(shí)代的發(fā)展,人們?cè)诶帽O(jiān)控程序編寫程序的過程中發(fā)現(xiàn)很多程序都有公共的部分。例如,通過鍵盤進(jìn)行文字輸入,顯示器進(jìn)行數(shù)據(jù)展示等,如果每編寫一個(gè)新的應(yīng)用程序都需要相同的處理的話,那真是太浪費(fèi)時(shí)間了。因此,基本的輸入輸出部分的程序就被追加到了監(jiān)控程序中。初期的操作系統(tǒng)就是這樣誕生了。
類似的想法可以共用,人們又發(fā)現(xiàn)有更多的應(yīng)用程序可以追加到監(jiān)控程序中,比如硬件控制程序
,編程語(yǔ)言處理器(匯編、編譯、解析)
以及各種應(yīng)用程序等,結(jié)果就形成了和現(xiàn)在差異不大的操作系統(tǒng),也就是說,其實(shí)操作系統(tǒng)是多個(gè)程序的集合體。
我在 程序員需要了解的硬核知識(shí)之CPU這篇文章中提到了匯編語(yǔ)言,這里簡(jiǎn)單再提一下。匯編語(yǔ)言是一種低級(jí)語(yǔ)言,也被稱為
符號(hào)語(yǔ)言
。匯編語(yǔ)言是第二代計(jì)算機(jī)語(yǔ)言,在匯編語(yǔ)言中,用助記符代替機(jī)器指令的操作碼,用地址符號(hào)或標(biāo)號(hào)代替指令或操作數(shù)的地址。用一些容易理解和記憶的字母,單詞來代替一個(gè)特定的指令,比如:用ADD
代表數(shù)字邏輯上的加減,MOV
代表數(shù)據(jù)傳遞等等,通過這種方法,人們很容易去閱讀已經(jīng)完成的程序或者理解程序正在執(zhí)行的功能,對(duì)現(xiàn)有程序的bug修復(fù)以及運(yùn)營(yíng)維護(hù)都變得更加簡(jiǎn)單方便
可以說共用思想真是人類前進(jìn)的一大步,對(duì)于解放生產(chǎn)力而言簡(jiǎn)直是太重要了。
要把操作系統(tǒng)放在第一位
對(duì)于程序員來說,程序員創(chuàng)造的不是硬件,而是各種應(yīng)用程序,但是如果程序員只做應(yīng)用不懂硬件層面的知識(shí)的話,是無法成為硬核程序員的。現(xiàn)在培訓(xùn)機(jī)構(gòu)培養(yǎng)出了一批怎么用的人才,卻沒有培訓(xùn)出為什么這么做的人才,畢竟為什么
不是培訓(xùn)機(jī)構(gòu)教的,而是學(xué)校教的,我很相信耗子叔說的話:學(xué)習(xí)沒有速成這回事。言歸正題。
在操作系統(tǒng)誕生之后,程序員不需要在硬件層面考慮問題,所以程序員的數(shù)量就增加了。哪怕自稱對(duì)硬件一竅不通
的人也可能制作出一個(gè)有模有樣的程序。不過,要想成為一個(gè)全面的程序員,有一點(diǎn)需要清楚的就是,掌握硬件的基本知識(shí),并借助操作系統(tǒng)進(jìn)行抽象化,可以大大提高編程效率。
下面就看一下操作系統(tǒng)是如何給開發(fā)人員帶來便利的,在 Windows 操作系統(tǒng)下,用 C 語(yǔ)言制作一個(gè)具有表示當(dāng)前時(shí)間功能的應(yīng)用。time()
是用來取得當(dāng)前日期和時(shí)間的函數(shù),printf()
是把結(jié)果打印到顯示器上的函數(shù),如下:
- #include <stdio.h>
- #include <time.h>
- void main(){
- // 保存當(dāng)前日期和時(shí)間信息
- time_t tm;
- // 取得當(dāng)前的日期和時(shí)間
- time(&tm);
- // 在顯示器上顯示日期和時(shí)間
- printf("%s\n", ctime(&tm));
- }
讀者可以自行運(yùn)行程序查看結(jié)果,我們主要關(guān)注硬件在這段代碼中做了什么事情
- 通過 time_t tm,為 time_t 類型的變量申請(qǐng)分配內(nèi)存空間;
- 通過 time(&tm) ,將當(dāng)前的日期和時(shí)間數(shù)據(jù)保存到變量的內(nèi)存空間中
- 通過 printf("%sn",ctime(&tm)), 把變量?jī)?nèi)存空間的內(nèi)容輸出到顯示器上。
應(yīng)用的可執(zhí)行文件指的是,計(jì)算機(jī)的 CPU 可以直接解釋并運(yùn)行的本地代碼,不過這些代碼是無法直接控制硬件的,事實(shí)上,這些代碼是通過操作系統(tǒng)來間接控制硬件的。變量中涉及到的內(nèi)存分配情況,以及 time() 和 printf() 這些函數(shù)的運(yùn)行結(jié)果,都不是面向硬件而是面向操作系統(tǒng)
的。操作系統(tǒng)收到應(yīng)用發(fā)出的指令后,首先會(huì)對(duì)該指令進(jìn)行解釋,然后會(huì)對(duì) 時(shí)鐘IC
和顯示器用的 I/O 進(jìn)行控制。
計(jì)算機(jī)中都安裝有保存日期和時(shí)間的實(shí)時(shí)時(shí)鐘(Real-time clock),上面提到的時(shí)鐘IC 就是值該實(shí)時(shí)時(shí)鐘。
系統(tǒng)調(diào)用和編程語(yǔ)言的移植性
操作系統(tǒng)控制硬件的功能,都是通過一些小的函數(shù)集合體的形式來提供的。這些函數(shù)以及調(diào)用函數(shù)的行為稱為系統(tǒng)調(diào)用
,也就是通過應(yīng)用進(jìn)而調(diào)用操作系統(tǒng)的意思。在前面的程序中用到了 time()
以及 printf()
函數(shù),這些函數(shù)內(nèi)部也封裝了系統(tǒng)調(diào)用。
C 語(yǔ)言等高級(jí)編程語(yǔ)言并不依存于特定的操作系統(tǒng),這是因?yàn)槿藗兿M还苁?code>Windows 操作系統(tǒng)還是 Linux
操作系統(tǒng)都能夠使用相同的源代碼。因此,高級(jí)編程語(yǔ)言的機(jī)制就是,使用獨(dú)自的函數(shù)名,然后在編譯的時(shí)候?qū)⑵滢D(zhuǎn)換為系統(tǒng)調(diào)用的方式(也有可能是多個(gè)系統(tǒng)調(diào)用的組合)。也就是說,高級(jí)語(yǔ)言編寫的應(yīng)用在編譯后,就轉(zhuǎn)換成了利用系統(tǒng)調(diào)用的本地代碼。
不過,在高級(jí)語(yǔ)言中也存在直接調(diào)用系統(tǒng)調(diào)用的編程語(yǔ)言,不過,利用這種方式做成應(yīng)用,移植性并不友好。
移植性:移植性指的是同樣的程序在不同操作系統(tǒng)下運(yùn)行時(shí)所花費(fèi)的時(shí)間,時(shí)間越少證明移植性越好。
操作系統(tǒng)和高級(jí)編程語(yǔ)言使硬件抽象化
通過使用操作系統(tǒng)提供的系統(tǒng)調(diào)用,程序員不必直接編寫控制硬件的程序,而且,通過使用高級(jí)編程語(yǔ)言,有時(shí)也無需考慮系統(tǒng)調(diào)用的存在,系統(tǒng)調(diào)用往往是自動(dòng)觸發(fā)的,操作系統(tǒng)和高級(jí)編程語(yǔ)言能夠使硬件抽象化,這很了不起。
下面讓我們看一個(gè)硬件抽象化的具體實(shí)例
- #include <stdio.h>
- void main(){
- // 打開文件
- FILE *fp = fopen("MyFile.txt","w");
- // 寫入文件
- fputs("你好", fp);
- // 關(guān)閉文件
- fclose(fp);
- }
上述代碼使用 C 編寫的程序,fputs()
是用來往文件中寫入字符串的函數(shù),fclose()
是用來關(guān)閉文件的函數(shù)。
上述應(yīng)用在編譯運(yùn)行后,會(huì)向文件中寫入 "你好" 字符串。文件是操作系統(tǒng)對(duì)磁盤空間的抽象化,就如同我們?cè)?程序員需要了解的硬核知識(shí)之磁盤 這篇文章提到的一樣,磁盤就如同樹的年輪,磁盤的讀寫是以扇區(qū)為單位的,通過磁道來尋址,如果直接對(duì)硬件讀寫的話,那么就會(huì)變?yōu)橥ㄟ^向磁盤用的 I/O 指定扇區(qū)位置來對(duì)數(shù)據(jù)進(jìn)行讀寫了。
但是,在上面代碼中,扇區(qū)壓根就沒有出現(xiàn)過傳遞給 fopen() 函數(shù)的參數(shù),是文件名 MyFile.txt
和指定文件寫入的 w
。傳遞給 fputs() 的參數(shù),是往文件中寫入的字符串"你好" 和 fp,傳遞給 fclose() 的參數(shù),也僅僅是 fp,也就是說磁盤通過打開文件這個(gè)操作,把磁盤抽象化了,打開文件這個(gè)操作就可以說是操作硬件的指令。
下面讓我們來看一下代碼清單中 fp 的功能,變量 fp 中被賦予的是 fopen() 函數(shù)的返回值,該值被稱為文件指針
。應(yīng)用打開文件后,操作系統(tǒng)就會(huì)自動(dòng)申請(qǐng)分配用來管理文件讀寫的內(nèi)存空間。內(nèi)存地址可以通過 fopen() 函數(shù)的返回值獲得。用 fopen() 打開文件后,接下來就是通過制定的文件指針進(jìn)行操作,正因?yàn)槿绱?,fputs() 和 fclose() 以及 fclose() 參數(shù)中都制定了文件指針。
由此我們可以得出一個(gè)結(jié)論,應(yīng)用程序是通過系統(tǒng)調(diào)用,磁盤抽象來實(shí)現(xiàn)對(duì)硬盤的控制的。
Windows 操作系統(tǒng)的特征
Windows 操作系統(tǒng)是世界上用戶數(shù)量最龐大的群體,作為 Windows 操作系統(tǒng)的資深
用戶,你都知道 Windows 操作系統(tǒng)有哪些特征嗎?下面列舉了一些 Windows 操作系統(tǒng)的特性
- Windows 操作系統(tǒng)有兩個(gè)版本:32位和64位
- 通過
API
函數(shù)集成來提供系統(tǒng)調(diào)用 - 提供了采用圖形用戶界面的用戶界面
- 通過
WYSIWYG
實(shí)現(xiàn)打印輸出,WYSIWYG 其實(shí)就是 What You See Is What You Get ,值得是顯示器上顯示的圖形和文本都是可以原樣輸出到打印機(jī)打印的。 - 提供多任務(wù)功能,即能夠同時(shí)開啟多個(gè)任務(wù)
- 提供網(wǎng)絡(luò)功能和數(shù)據(jù)庫(kù)功能
- 通過即插即用實(shí)現(xiàn)設(shè)備驅(qū)動(dòng)的自設(shè)定
這些是對(duì)程序員來講比較有意義的一些特征,下面針對(duì)這些特征來進(jìn)行分別的介紹
32位操作系統(tǒng)
這里表示的32位操作系統(tǒng)表示的是處理效率最高的數(shù)據(jù)大小。Windows 處理數(shù)據(jù)的基本單位是 32 位。這與最一開始在 MS-DOS
等16位操作系統(tǒng)不同,因?yàn)樵?6位操作系統(tǒng)中處理32位數(shù)據(jù)需要兩次,而32位操作系統(tǒng)只需要一次就能夠處理32位的數(shù)據(jù),所以一般在 windows 上的應(yīng)用,它們的最高能夠處理的數(shù)據(jù)都是 32 位的。
比如,用 C 語(yǔ)言來處理整數(shù)數(shù)據(jù)時(shí),有8位的 char
類型,16位的short
類型,以及32位的long
類型三個(gè)選項(xiàng),使用位數(shù)較大的 long 類型進(jìn)行處理的話,增加的只是內(nèi)存以及磁盤的開銷,對(duì)性能影響不大。
現(xiàn)在市面上大部分都是64位操作系統(tǒng)了,64位操作系統(tǒng)也是如此。
通過 API 函數(shù)集來提供系統(tǒng)調(diào)用
Windows 是通過名為 API
的函數(shù)集來提供系統(tǒng)調(diào)用的。API是聯(lián)系應(yīng)用程序和操作系統(tǒng)之間的接口,全稱叫做 Application Programming Interface
,應(yīng)用程序接口。
當(dāng)前主流的32位版 Windows API 也稱為 Win32 API
,之所以這樣命名,是需要和不同的操作系統(tǒng)進(jìn)行區(qū)分,比如最一開始的 16 位版的 Win16 API
,和后來流行的 Win64 API
。
API 通過多個(gè) DLL 文件來提供,各個(gè) API 的實(shí)體都是用 C 語(yǔ)言編寫的函數(shù)。所以,在 C 語(yǔ)言環(huán)境下,使用 API 更加容易,比如 API 所用到的 MessageBox()
函數(shù),就被保存在了 Windows 提供的 user32.dll 這個(gè) DLL 文件中。
提供采用了 GUI 的用戶界面
GUI(Graphical User Interface)
指得就是圖形用戶界面,通過點(diǎn)擊顯示器中的窗口以及圖標(biāo)等可視化的用戶界面,舉個(gè)例子:Linux 操作系統(tǒng)就有兩個(gè)版本,一種是簡(jiǎn)潔版,直接通過命令行控制硬件,還有一種是可視化版,通過光標(biāo)點(diǎn)擊圖形界面來控制硬件。
通過 WYSIWYG 實(shí)現(xiàn)打印輸出
WYSIWYG 指的是顯示器上輸出的內(nèi)容可以直接通過打印機(jī)打印輸出。在 Windows 中,顯示器和打印機(jī)被認(rèn)作同等的圖形輸出設(shè)備處理的,該功能也為 WYSIWYG 提供了條件。
借助 WYSIWYG 功能,程序員可以輕松不少。最初,為了是現(xiàn)在顯示器中顯示和在打印機(jī)中打印,就必須分別編寫各自的程序,而在 Windows 中,可以借助 WYSIWYG 基本上在一個(gè)程序中就可以做到顯示和打印這兩個(gè)功能了。
提供多任務(wù)功能
多任務(wù)指的就是同時(shí)能夠運(yùn)行多個(gè)應(yīng)用程序的功能,Windows 是通過時(shí)鐘分割
技術(shù)來實(shí)現(xiàn)多任務(wù)功能的。時(shí)鐘分割指的是短時(shí)間間隔內(nèi),多個(gè)程序切換運(yùn)行的方式。在用戶看來,就好像是多個(gè)程序在同時(shí)運(yùn)行,其底層是 CPU 時(shí)間切片
,這也是多線程多任務(wù)的核心。
提供網(wǎng)絡(luò)功能和數(shù)據(jù)庫(kù)功能
Windows 中,網(wǎng)絡(luò)功能是作為標(biāo)準(zhǔn)功能提供的。數(shù)據(jù)庫(kù)(數(shù)據(jù)庫(kù)服務(wù)器)功能有時(shí)也會(huì)在后面追加。網(wǎng)絡(luò)功能和數(shù)據(jù)庫(kù)功能雖然并不是操作系統(tǒng)不可或缺的,但因?yàn)樗鼈兒筒僮飨到y(tǒng)很接近,所以被統(tǒng)稱為中間件
而不是應(yīng)用。意思是處于操作系統(tǒng)和應(yīng)用的中間層,操作系統(tǒng)和中間件組合在一起,稱為系統(tǒng)軟件
。應(yīng)用不僅可以利用操作系統(tǒng),也可以利用中間件的功能。
相對(duì)于操作系統(tǒng)一旦安裝就不能輕易更換,中間件可以根據(jù)需要進(jìn)行更換,不過,對(duì)于大部分應(yīng)用來說,更換中間件的話,會(huì)造成應(yīng)用也隨之更換,從這個(gè)角度來說,更換中間件也不是那么容易。
通過即插即用實(shí)現(xiàn)設(shè)備驅(qū)動(dòng)的自動(dòng)設(shè)定
即插即用(Plug-and-Play)
指的是新的設(shè)備連接(plug) 后就可以直接使用的機(jī)制,新設(shè)備連接計(jì)算機(jī)后,計(jì)算機(jī)就會(huì)自動(dòng)安裝和設(shè)定用來控制該設(shè)備的驅(qū)動(dòng)程序
設(shè)備驅(qū)動(dòng)是操作系統(tǒng)的一部分,提供了同硬件進(jìn)行基本的輸入輸出的功能。鍵盤、鼠標(biāo)、顯示器、磁盤裝置等,這些計(jì)算機(jī)中必備的硬件的設(shè)備驅(qū)動(dòng),一般都是隨操作系統(tǒng)一起安裝的。
有時(shí) DLL 文件也會(huì)同設(shè)備驅(qū)動(dòng)文件一起安裝。這些 DLL 文件中存儲(chǔ)著用來利用該新追加的硬件API,通過 API ,可以制作出運(yùn)行該硬件的心應(yīng)用。