源檔案的編譯過程包含兩個主要
階段,而它們之間的轉換是自動的。先說說要實現一個程式功能要經曆的步驟吧
step1:當然就是在編輯視窗(用進階語言)輸入你的原程式 (f.c)
step2:編譯你的原程式 編譯成電腦能夠識別的2進位形式的目標代碼(f.o)
step3:將上面的目標代碼 輸入記憶體與系統提供的庫函數和其他一些目標代碼相串連 串連成可以執行的exe檔案 f.exe
step4:再將可以執行的exe檔案調入記憶體運行
第一個階段是預先處理階段,在正式的編譯階段之前進行。預先處理階段將根據已放置在檔案中的預先處理指令來修改源檔案的內容。#include指令就是一個預先處理指令,它把標頭檔的內容添加到.cpp檔案中還有其他許多預先處理指令
這個在編譯之前修改源檔案的方式提供了很大的靈活性,以適應不同的電腦和作業系統環境的限制。一個環境需要的代碼跟另一個環境所需的代碼可能有所不同,因為可用的硬體或作業系統是不同的。在許多情況下,可以把用於不同環境的代碼放在同一個檔案中,再在預先處理階段修改代碼,使之適應當前的環境。前置處理器顯示為一個獨立的操作,但一般不能獨立於編譯器來執行這個操作。調用編譯器會自動執行預先處理過程,之後才編譯代碼。編譯器為給定源檔案輸出的是機器碼,執行這個過程需要較長時間。在對象檔案之間並沒有建立任何串連。對應於某個源檔案的對象檔案包含在其他源檔案中定義的函數引用或其他指定項的引用,而這些函數或項仍沒有被解析。同樣,也沒有建立同庫函數的連結。實際上,這些函數的代碼並不是檔案的一部分。這些工作是由連結程式(有時稱為連結編輯器)完成的。 編譯方式是指利用事先編好的一個稱為編譯器的機器語言程式,作為系統軟體存放在電腦內,當使用者將進階語言編寫的來源程式輸入電腦後,編譯器便把來源程式整個地翻譯成用機器語言表示的與之等價的目標程式,然後電腦再執行該目標程式,以完成來源程式要處理的運算並取得結果。
第二個是連結程式階段把所有對象檔案中的機器碼組合在一起,並解析它們之間的交叉引用。它還整合了對象模組所使用的庫函數的代碼。這是連結程式的一種簡化表示,因為這裡假定在可執行模組中,模組之間的所有連結都是靜態建立的。實際上有些連結是動態,即這些連結是在程式執行時建立的。
連結程式靜態地建立函數之間的連結,即在程式執行之前建立組成程式的源檔案中所包含的函數連結。動態建立的函數之間的連結(在程式執行過程中建立的連結)將函數編譯並連結起來,建立另一種可執行模組—— 動態連結程式庫或共用庫。動態連結程式庫中的函數連結是在程式調用函數時才建立的,在程式調用之前,該連結是不存在的。
動態連結程式庫有幾個重要的優點。一個主要的優點是動態連結程式庫中的函數可以在幾個並存執行的程式之間共用,這將節省相同函數佔用的記憶體空間。另一個優點是動態連結程式庫在調用其中的函數之前是不會載入到記憶體中的。也就是說,如果不使用給定動態連結程式庫中的函數,該動態連結程式庫就不會佔用記憶體空間。
下面舉出一些詳細例子:
現在的Java是運行時編譯。和C++的編譯方式完全不同。所有的對象都是動態分配記憶體的,而且Java的優點在於你不用delete,記憶體撤銷由虛擬機器負責
在c++中對記憶體的管理分為三種:
(1)從靜態儲存地區分配。記憶體在程式編譯的時候就已經分配好,這塊記憶體在程式的整個運行期間都存在。例如全域變數,static變數。
(2)在棧上建立。在執行函數時,函數內局部變數的儲存單元都可以在棧上建立,函數執行結束時這些儲存單元自動被釋放。棧記憶體配置運算內建於處理器的指令集中,效率很高,但是分配的記憶體容量有限。
(3)從堆上分配,亦稱動態記憶體分配。程式在啟動並執行時候用malloc或new申請任意多少的記憶體,程式員自己負責在何時用free或delete釋放記憶體。動態記憶體的生存期由我們決定,使用非常靈活,但問題也最多