什么是編譯器?(程序是怎么跑起來的)

我們平時所說的程序,是指雙擊后就可以直接運行的程序,這樣的程序被稱為可執行程序(Executable Program)。在 Windows 下,可執行程序的后綴有 .exe 和 .com(其中 .exe 比較常見);在類 UNIX 系統(Linux、Mac OS 等)下,可執行程序沒有特定的后綴,系統根據文件的頭部信息來判斷是否是可執行程序。

可執行程序的內部是一系列計算機指令和數據的集合,它們都是二進制形式的,CPU 可以直接識別,毫無障礙;但是對于程序員,它們非常晦澀,難以記憶和使用。

例如,在屏幕上輸出“VIP會員”,C語言的寫法為:

puts("VIP會員");

二進制的寫法為:


你感受一下,直接使用二進制是不是想撞墻,是不是受到一噸重的傷害?

在計算機發展的初期,程序員就是使用這樣的二進制指令來編寫程序的,那個拓荒的年代還沒有編程語言。

直接使用二進制指令編程對程序員來說簡直是噩夢,尤其是當程序比較大的時候,不但編寫麻煩,需要頻繁查詢指令手冊,而且除錯會異常苦惱,要直接面對一堆二進制數據,讓人眼花繚亂。另外,用二進制指令編程步驟繁瑣,要考慮各種邊界情況和底層問題,開發效率十分低下。

這就倒逼程序員開發出了編程語言,提高自己的生產力,例如匯編、C語言、cpp、Java、py、Go語言等,都是在逐步提高開發效率。至此,編程終于不再是只有極客能做的事情了,不了解計算機的讀者經過一定的訓練也可以編寫出有模有樣的程序。

什么是編譯器

C語言代碼由固定的詞匯按照固定的格式組織起來,簡單直觀,程序員容易識別和理解,但是對于CPU,C語言代碼就是天書,根本不認識,CPU只認識幾百個二進制形式的指令。這就需要一個工具,將C語言代碼轉換成CPU能夠識別的二進制指令,也就是將代碼加工成 .exe 程序;這個工具是一個特殊的軟件,叫做編譯器(Compiler)。

編譯器能夠識別代碼中的詞匯、句子以及各種特定的格式,并將他們轉換成計算機能夠識別的二進制形式,這個過程稱為編譯(Compile)。

編譯也可以理解為“翻譯”,類似于將中文翻譯成英文、將英文翻譯成象形文字,它是一個復雜的過程,大致包括詞法分析、語法分析、語義分析、性能優化、生成可執行文件五個步驟,期間涉及到復雜的算法和硬件架構。對于學計算機或者軟件的大學生,“編譯原理”是一門專業課程,有興趣的讀者請自行閱讀《編譯原理》一書,這里我們不再展開講解。

注意:不了解編譯原理并不影響我們學習C語言,我也不建議初學者去鉆研編譯原理,貪多嚼不爛,不要把自己繞進去。

C語言的編譯器有很多種,不同的平臺下有不同的編譯器,例如:

  • Windows 下常用的是微軟編譯器(cl.exr),它被集成在 Visual Studio 或 Visual C++ 中,一般不單獨使用;
  • Linux 下常用的是 GUN 組織開發的?GCC,很多 Linux 發行版都自帶 GCC;
  • Mac 下常用的是?LLVM/Clang,它被集成在 Xcode 中(Xcode 以前集成的是 GCC,后來由于 GCC 的不配合才改為 LLVM/Clang,LLVM/Clang 的性能比 GCC 更加強大)。


你的代碼語法正確與否,編譯器說了才算,我們學習C語言,從某種意義上說就是學習如何使用編譯器,讓編譯器生成可執行程序(例如 Windows 下的 .exe 程序)。

編譯器可以 100% 保證你的代碼從語法上講是正確的,因為哪怕有一點小小的錯誤,編譯也不能通過,編譯器會告訴你哪里錯了,便于你的更改。

什么是集成開發環境

實際開發中,除了編譯器是必須的工具,我們往往還需要很多其他輔助軟件,例如:

  • 編輯器:用來編寫代碼,并且給代碼著色,以方便閱讀;
  • 代碼提示器:輸入部分代碼,即可提示全部代碼,加速代碼的編寫過程;
  • 調試器:觀察程序的每一個運行步驟,發現程序的邏輯錯誤;
  • 項目管理工具:對程序涉及到的所有資源進行管理,包括源文件、圖片、視頻、第三方庫等;
  • 漂亮的界面:各種按鈕、面板、菜單、窗口等控件整齊排布,操作更方便。


這些工具通常被打包在一起,統一發布和安裝,例如 Visual Studio、Dev C++、Xcode、Visual C++ 6.0、C-Free、Code::Blocks 等,它們統稱為集成開發環境(IDE,Integrated Development Environment)。

集成開發環境就是一系列開發工具的組合套裝。這就好比臺式機,一個臺式機的核心部件是主機,有了主機就能獨立工作了,但是我們在購買臺式機時,往往還要附帶上顯示器、鍵盤、鼠標、U盤、攝像頭等外圍設備,因為只有主機太不方便了,必須有外設才能玩的爽。

集成開發環境也是這個道理,只有編譯器不方便,所以還要增加其他的輔助工具。

1) 源文件(Source File)

在開發軟件的過程中,我們需要將編寫好的代碼(Code)保存到一個文件中,這樣代碼才不會丟失,才能夠被編譯器找到,才能最終變成可執行文件。這種用來保存代碼的文件就叫做源文件(Source File)。

每種編程語言的源文件都有特定的后綴,以方便被編譯器識別,被程序員理解。源文件后綴大都根據編程語言本身的名字來命名,例如:

C語言源文件的后綴是.c;
C++語言(C Plus Plus)源文件的后綴是.cpp;
Java?源文件的后綴是.java;
Python?源文件的后綴是.py;
JavaScript?源文件后置是.js。

源文件其實就是純文本文件,它的內部并沒有特殊格式,能證明這一結論的典型例子是:在 Windows 下用記事本程序新建一個文本文檔,并命名為demo.txt,輸入一段C語言代碼并保存,然后將該文件強制重命名為demo.c(后綴從.txt變成了.c),發現編譯器依然能夠正確識別其中的C語言代碼,并順利生成可執行文件。

源文件的后綴僅僅是為了表明該文件中保存的是某種語言的代碼(例如.c文件中保存的是C語言代碼),這樣程序員更加容易區分,編譯器也更加容易識別,它并不會導致該文件的內部格式發生改變。

C++ 是站在C語言的肩膀上發展期來的,是在C語言的基礎上進行的擴展,C++ 包含了C語言的全部內容,將C語言代碼放在.cpp文件中不會有錯,很多初學者都是這么做的,很多大學老師也是這么教的。但是,我還是強烈建議將C語言代碼放在.c文件中,這樣能夠更加嚴格地遵循C語言的語法,也能夠更加清晰地了解C語言和C++的區別。

2) 工程/項目(Project)

一個真正的程序(也可以說軟件)往往包含多項功能,每一項功能都需要幾十行甚至幾千行、幾萬行的代碼來實現,如果我們將這些代碼都放到一個源文件中,那將會讓人崩潰,不但源文件打開速度極慢,代碼的編寫和維護也將變得非常困難。

在實際開發中,程序員都是將這些代碼分門別類地放到多個源文件中。除了這些成千上萬行的代碼,一個程序往往還要包含圖片、視頻、音頻、控件、庫(也可以說框架)等其它資源,它們也都是一個一個地文件。

為了有效地管理這些種類繁雜、數目眾多的文件,我們有理由把它們都放到一個目錄(文件夾)下,并且這個目錄下只存放與當前程序有關的資源。實際上 IDE 也是這么做的,它會為每一個程序都創建一個專門的目錄,將用到的所有文件都集中到這個目錄下,并對它們進行便捷的管理,比如重命名、刪除文件、編輯文件等。

這個為當前程序配備的專用文件夾,在 IDE 中也有一個專門的稱呼,叫做“Project”,翻譯過來就是“工程”或者“項目”。在 VC 6.0 下,這叫做一個“工程”,而在 VS 下,這又叫做一個“項目”,它們只是單詞“Project”的不同翻譯而已,實際上是一個概念。

3) 工程類型/項目類型

“程序”是一個比較寬泛的稱呼,它可以細分為很多種類,例如:

  • 有的程序不帶界面,完全是“黑屏”的,只能輸入一些字符或者命令,稱為控制臺程序(Console Application),例如 Windows 下的 cmd.exe,Linux 或 Mac OS 下的終端(Terminal)。
  • 有的程序帶界面,看起來很漂亮,能夠使用鼠標點擊,稱為GUI程序(Graphical User Interface Program),例如 QQ、迅雷、Chrome 等。
  • 有的程序不單獨出現,而是作為其它程序的一個組成部分,普通用戶很難接觸到它們,例如靜態庫、動態庫等。


不同的程序對應不同的工程類型(項目類型),使用 IDE 時必須選擇正確的工程類型才能創建出我們想要的程序。換句話說,IDE 包含了多種工程類型,不同的工程類型會創建出不同的程序。

不同的工程類型本質上是對 IDE 中各個參數的不同設置;我們也可以創建一個空白的工程類型,然后自己去設置各種參數(不過一般不這樣做)。

控制臺程序對應的工程類型為“Win32控制臺程序(Win32 Console Application)”,GUI程序對應的工程類型為“Win32程序(Win32 Application)”。

控制臺程序是 DOS 時代的產物了,它沒有復雜的功能,沒有漂亮的界面,只能看到一些文字,雖然枯燥無趣,也不實用,但是它非常簡單,不受界面的干擾,所以適合入門,我強烈建議初學者從控制臺程序學起。等大家對編程掌握的比較熟練了,能編寫上百行的代碼了,再慢慢過渡到GUI程序。

4) 鏈接(Link)

上節我們講到,源代碼經過編譯(Compile)后就變成了可執行文件,其實這種說法有點籠統,甚至從嚴格意義上來講是錯誤的。源代碼要經過編譯(Compile)和鏈接(Link)兩個過程才能變成可執行文件。

編譯器一次只能編譯一個源文件,如果當前程序包含了多個源文件,那么就需要編譯多次。編譯器每次編譯的結果是產生一個中間文件(可以認為是一種臨時文件),而不是最終的可執行文件。中間文件已經非常接近可執行文件了,它們都是二進制格式,內部結構也非常相似。

將當前程序的所有中間文件以及系統庫(暫時可以理解為系統中的一些組件)組合在一起,才能形成最終的可執行文件,這個組合的過程就叫做鏈接(Link)。完成鏈接功能的軟件叫做鏈接器(Linker)。

如果程序只包含了一個源文件,是不是就不需要鏈接了呢?不是的!

經過編譯后程序雖然只有一個中間文件,不再需要和其它的中間文件組合了,但是這個唯一的中間文件還需要和系統庫組合,這個過程也是鏈接。也就是說,不管有多少個源文件,都必須經過編譯和鏈接兩個過程才能生成可執行文件。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/444082.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/444082.shtml
英文地址,請注明出處:http://en.pswp.cn/news/444082.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C++std命名空間和頭文件詳解

一個中大型軟件往往由多名程序員共同開發,會使用大量的變量和函數,不可避免地會出現變量或函數的命名沖突。當所有人的代碼都測試通過,沒有問題時,將它們結合到一起就有可能會出現命名沖突。 例如小李和小韓都參與了一個文件管理系…

C++ new和delete

在C語言中,動態分配內存用 malloc() 函數,釋放內存用 free() 函數。如下所示: int *p (int*) malloc( sizeof(int) * 10 ); //分配10個int型的內存空間free(p); //釋放內存 在cpp中,這兩個函數仍然可以使用,但是C又…

Java 的內存管理機制是怎樣的?

Java 的內存管理機制是怎樣的?

leetcode1103. 分糖果 II 該模擬就模擬,別老想著優化

排排坐,分糖果。 我們買了一些糖果 candies,打算把它們分給排好隊的 n num_people 個小朋友。 給第一個小朋友 1 顆糖果,第二個小朋友 2 顆,依此類推,直到給最后一個小朋友 n 顆糖果。 然后,我們再回到…

leetcode912. 排序數組 有范圍的排序統統用桶排序

給你一個整數數組 nums&#xff0c;請你將該數組升序排列。 示例 1&#xff1a; 輸入&#xff1a;nums [5,2,3,1] 輸出&#xff1a;[1,2,3,5] 示例 2&#xff1a; 輸入&#xff1a;nums [5,1,1,2,0,0] 輸出&#xff1a;[0,0,1,1,2,5] 提示&#xff1a; 1 < nums.len…

隊列【數據結構】

注意 我們的銷毀隊列是否能夠成功取決申請空間的方式&#xff0c;動態申請出來的空間都是可以進行銷毀的&#xff0c;對于靜態的話是不能直接進行銷毀的 ADT 相當于是c當中的類結構&#xff0c;是處理數據時&#xff0c;提前對數據進行一定的管理操作&#xff0c;就是將某一件事…

C++繼承詳解

廢話不多說直接上代碼 class 派生類名:&#xff3b;繼承方式&#xff3d; 基類名{ 派生類新增加的成員 }; 繼承方式限定了基類成員在派生類中的訪問權限&#xff0c;包括 public&#xff08;公有的&#xff09;、private&#xff08;私有的&#xff09;和 protected&…

串【數據結構F】

先來講解一下串結構的概念性質的東西&#xff0c;以及我們需要注意的一些問題 串結構簡單的ADT以及一些基本的操作 最小操作函數&#xff1a;就是功能已經達到了最小的功能實現了&#xff0c;不能繼續執行更大的功能&#xff0c;類似于我們在家蓋房子一樣&#xff0c;水泥的…

C++ STL與迭代器

將容器類模板實例化時&#xff0c;會指明容器中存放的元素是什么類型的&#xff1a;可以存放基本類型的變量&#xff0c;也可以存放對象。 對象或基本類型的變量被插入容器中時&#xff0c;實際插入的是對象或變量的一個復制品。 STL 中的許多算法&#xff08;即函數模板&…

在JSP頁面中輸出JSON格式數據

JSON-taglib是一套使在JSP頁面中輸出JSON格式數據的標簽庫。 JSON-taglib主頁&#xff1a; http://json-taglib.sourceforge.net/index.html JAR包下載地址&#xff1a; http://sourceforge.net/projects/json-taglib/files/latest/download 使用方法&#xff1a; 1、下載js…

git/github使用完整教程(1)基礎

安裝git 在Linux上安裝Git 首先輸入git&#xff0c;看看系統有沒有安裝Git&#xff1a; $ git The program git is currently not installed. You can install it by typing: sudo apt-get install git像上面的命令&#xff0c;有很多Linux會友好地告訴你Git沒有安裝&#x…

git/github使用完整教程(2)分支

分支 首先&#xff0c;我們創建dev分支&#xff0c;然后切換到dev分支&#xff1a; $ git checkout -b dev Switched to a new branch devgit checkout命令加上-b參數表示創建并切換&#xff0c;相當于以下兩條命令&#xff1a; $ git branch dev $ git checkout dev Switch…

數組【數據結構】

前提 數組的定義以及數組的延伸 這種不好進行理解&#xff0c;那么我們下面以二維數組進行解釋 多維數組的數據特點 存儲數組結構的兩種方式 問題抽象總結