操作系統,CPU,編譯器,運行時庫,系統調用的關係 之 編譯器篇

操作系統,CPU,編譯器,運行時庫,系統調用。這是計算機科學中相對高大上的幾個概念,許多科班出身的碼農甚至也搞不清楚一個簡單代碼執行過程中,哪塊是操作系統控制,哪塊是編譯器控制,CPU到底扮演了何種角色,什麼是運行時庫。

思考問題,我們首先要把握宏觀,掌握好了大致情況,然後再對自己感興趣的節點做深入分析。這是一種很實用的思考問題的方式,不會讓你陷入“局部最優解”,更重要的是,它可以讓你更深刻地理解問題的本質,遇到困難時不致迷茫。本文將梳理計算機科學中一些基本的概念,我們將沿着程序從出生到消亡的脈絡,探討CPU,探討編譯器,探討操作系統和運行時庫,以此來深入理解計算機系統。


編譯器


         編譯器絕對是計算機科學中殿堂級的領域,能夠寫編譯器的都是大牛中的大牛,筆者依稀記得自己本科做編譯原理大作業的情境,那4張8K的紙愣是沒有畫出一個簡單語言的語法狀態轉移圖。今天,我們不談編譯器原理,只關注其作用。編譯器是高級語言到機器語言的轉換器。當你洋洋灑灑地寫完一萬行代碼時,那些struct、if、while除了你和C編譯器看得懂外,沒人能看得懂了,機器也不例外。機器只能看懂01碼,編譯器就是負責把源代碼翻譯成01碼的。Windows下.exe後綴的程序就是一串01碼,linux下你的a.out也是01碼,但是01碼絕對不止這些,linux下的.o和windows下的.dll也都是01碼,只不過這些01碼不能直接執行,而是由a.out和.exe程序調用。

         這就是編譯器了,其實你只要記住它是高級語言到機器語言的轉換器即可,這種工作在現實生活中叫:翻譯。有了編譯器,你的思想就結晶爲01碼了。

         沒有這麼簡單,我們還要再深入一層。都知道程序包括代碼數據,對於代碼其實我們能有個感官的認識,這主要因爲大家基本都學過彙編語言,代碼彙編的層面基本都轉化爲mov,jmp,add等指令了,相信許多人也寫過類似代碼,但是數據呢?編譯器如何“編譯”數據

         你該鄙視我了:數據這東西怎麼能“編譯”呢?是的,數據確實不是編譯的,你可以說它被編譯器“安置”在一個位置上,但是對於數據的理解絕對不止此。首先全局變量和局部變量有着重大的差別,還有就是那些看似簡單但是充滿着智慧的基本數據類型(int,short,double等),還有就是老生常談的字符串    

 

全局變量和局部變量


         最終的可執行文件以01碼存儲,這點已經確定。分析一個典型的可執行文件,以ELF文件(Linux下可執行文件)爲例,發現最終的01碼主要包括以下幾個部分:靜態數據區,代碼區,字符串常量區等等。其中你的全局變量就是存放在ELF文件的靜態數據區,代碼就是存放在代碼區,而像以如下方式聲明的字符串“hello world1”則是存儲在了字符串常量區:

                                                                                    char *str  ="hello world1";

         還有局部變量。記住,在可執行文件的01碼當中,不會有局部變量的位置,這是因爲局部變量是放到了程序的棧空間中。說到了棧,棧僅僅是在程序運行的時候纔會有的概念,所以在編譯器產生的01碼中,不會有類似於“局部變量區”的分塊。趁熱打鐵。以上我們解決了代碼的安置、全局變量以及字符串的安置,那麼局部變量是怎麼安置的呢,它總不會無緣無故地就出現了吧。所謂的局部變量就是在函數內部定義的變量,比如以下函數:

                                                           
 int func{
    int a;
    char b[2];
}

        其中,a和b都是局部變量,局部變量位於該函數的棧空間中。比如,當調用函數func時,程序的堆棧將會是如下的狀態:


        由於棧是一個動態的結構,只有在程序執行的時候纔會涉及,所以a和b變量肯定在是程序執行過程中產生的。所以已經不難理解了,每一個子函數彙編代碼的初始部分肯定會有一個壓棧的過程,上例中是壓入1個int和2個char。子函數中的對a和b的引用都被關聯到棧上的這塊區域。所以,局部變量和全局變量有着本質的不同:全局變量在01碼中就存在了,是靜態的,而局部變量在01碼中還僅僅是一些push變量,是動態的;全局變量將伴隨整個程序執行過程,而局部變量生命期只是短短的子函數執行時間。


基本數據類型


       幾乎所有C語言教科書的入門章節都是基本數據類型,在這裏我們不談那些強數據類型與弱數據類型的差別了,來點乾貨。爲什麼要說數據類型?源於我自己的一個疑惑。學計算機這幾年中,每當遇到數據類型的問題,我耳邊總是充斥着各種各樣的聲音:數據類型和編譯器相關,數據類型和操作系統相關,數據類型和CPU相關,數據類型和平臺相關。數據類型到底和什麼相關?

         不妨挨個來分析。首先數據類型肯定和CPU相關,比如32位和64位CPU的sizeof(char*)返回值就不一樣,說明由於CPU的不同數據的類型有很大的不同。和編譯器肯定也是相關的,數據類型不但包括該類型所佔內存的大小,還包括對於該種類型所施加的操作(這個定義和C++中的類很像,除了數據還應該有函數)。在數據類型的轉換操作中,不同編譯器的行爲很是不一樣。比如unsigned char類型強轉long類型,有些編譯器就可能會把long多出來的3個byte分別賦值爲0xFF,而有些編譯器則會將這3個byte賦值爲0x00。這樣,同一個操作在不同的編譯器上產生了不同的行爲與結果,而這些行爲都是對應程序靜態的01碼的,所以數據類型與編譯器也是相關的。對於操作系統,由於它也僅僅是一個程序而已,是一個“政府程序”,本身構建於CPU之上,所以不能說數據類型與操作系統相關。

         好,分析到這裏,我基本上是得出了一個結論,那就是數據類型是和CPU、編譯器相關,這就是某些人所談到的平臺。至於操作系統,我們姑且把它當作一個和普通程序無異的程序吧,只不過它手裏握有資源。

         說到這裏,編譯器就說完了。是的,編譯器用來產生01碼,產生的過程中用到了各種智慧!在這個階段,程序還是躺在硬盤上的一個代碼,靜靜地等待執行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章