C++ 程式設計
一個 編譯器 是一個將用一種 計算機語言(原始碼)編寫的 計算機程式 翻譯成等效的用計算機的原生 機器語言 編寫的程式的程式。這個翻譯過程,包括幾個不同的步驟,被稱為 編譯。由於編譯器本身就是一個程式,用計算機語言編寫,所以這種情況似乎是一個悖論,類似於 先有雞還是先有蛋 的困境。編譯器可能不是用最終可編譯的語言建立的,而是用之前可用的語言或甚至用機器程式碼建立的。
編譯器的 編譯 輸出是翻譯或 編譯 程式的結果。輸出中最重要的一部分儲存到一個名為 目標檔案 的檔案中,它包含將原始檔轉換為目標檔案的轉換。
然後,如果目標檔案是可執行格式,計算機可以執行(執行)該 編譯 程式的指令。但是,編譯還需要額外的步驟:預處理和連結。
定義編譯器在構建(建立)程式(可執行或不可執行)期間執行的時間和操作(即 編譯時操作)。C++ 語言中“static”的大多數用法與編譯時資訊直接相關。
編譯時執行的操作通常包括 詞法分析、語法分析、各種型別的 語義分析(例如,型別檢查、一些 型別轉換 和 模板例項化)以及 程式碼生成。
程式語言的定義將指定原始碼必須滿足的編譯時要求才能成功編譯。
編譯時發生在 連結時(將一個或多個編譯檔案的輸出連線在一起)和執行時(程式執行時)之前。在一些程式語言中,可能需要在執行時進行一些編譯和連結。
- 執行時
執行時 或 執行時間 從程式開始執行的那一刻開始,到程式退出時結束。在這個階段,編譯器無關緊要,沒有控制權。這是關於最佳化的最重要的位置(程式只編譯一次,但執行很多次)和除錯(跟蹤和互動只有在這個階段才能實現)。但執行時也是一些 型別轉換可能發生 的地方,執行時型別資訊 (RTTI) 與此相關。執行時的概念將在相關時再次提及。
這也被稱為掃描或 標記化。它發生在語法分析之前,並將程式碼轉換為 標記,這些標記是程式實際使用的程式碼部分。原始碼以字元(排列在行上)的形式表達為每個保留關鍵字的特殊標記序列,以及資料型別和識別符號以及值的標記。詞法分析器是編譯器的一部分,它從原始碼中刪除空格和其他不可編譯字元。它使用空格來分隔不同的標記,並忽略空格。
為了簡單說明這個過程
int main()
{
std::cout << "hello world" << std::endl;
return 0;
}
根據使用的詞法規則,它可能被 標記化 為
1 = string "int" 2 = string "main" 3 = opening parenthesis 4 = closing parenthesis 5 = opening brace 6 = string "std" 7 = namespace operator 8 = string "cout" 9 = << operator 10 = string ""hello world"" 11 = string "endl" 12 = semicolon 13 = string "return" 14 = number 0 15 = closing brace
因此,對於這個程式,詞法分析器可能會發送類似的東西
1 2 3 4 5 6 7 8 9 10 9 6 7 11 12 13 14 12 15
給下一個將要解析的語法分析器。當它可以處理數值並能夠區分語言語法(例如分號)和所有其他內容時,語法分析器更容易應用語言規則,並且知道每個事物的資料型別。
此步驟(有時也稱為語法檢查)確保程式碼有效,並將按順序組成可執行程式。語法分析器將規則應用於程式碼,檢查以確保每個左括號都有一個對應的右括號,每個宣告都有一個型別,以及該型別存在,以及……語法分析比詞法分析更復雜 =)。
例如
int main()
{
std::cout << "hello world" << std::endl;
return 0;
}
- 語法分析器將首先檢視字串“int”,將其與定義的關鍵字進行比較,並發現它是一個整數型別。
- 然後,分析器會將下一個標記視為識別符號,並檢查以確保它使用的是有效的識別符號名稱。
- 然後它將檢視下一個標記。因為它是一個左括號,所以它將“main”視為一個函式,而不是一個變數宣告(如果它找到一個分號)或一個整數變數的初始化(如果它找到一個等號)。
- 在左括號之後,它將找到一個右括號,這意味著該函式有 0 個引數。
- 然後它會檢視下一個標記,發現它是一個左大括號,所以它會認為這是函式 main 的實現,而不是 main 的宣告(如果下一個標記是分號的話),即使在 C++ 中不能宣告 main。它可能還會建立一個計數器來跟蹤語句塊的級別,以確保括號成對出現。*之後它會檢視下一個標記,可能不會對其進行任何操作,但然後它會看到 :: 運算子,並檢查 "std" 是否是一個有效的
名稱空間。 - 然後它會看到下一個標記 "cout" 作為 "std"
名稱空間中識別符號的名稱,並發現它是一個模板。 - 分析器會看到下一個標記 << 運算子,因此它會檢查 << 運算子是否可以與 cout 一起使用,以及下一個標記是否可以與 << 運算子一起使用。
- 下一個標記 ""hello world"" 後面的標記也會發生同樣的事情。然後它會再次遇到 "std" 標記,檢視它後面的 :: 運算子標記,並檢查
名稱空間是否再次存在,然後檢查 "endl" 是否在名稱空間中。 - 然後它會看到分號,所以它會將其視為語句的結束。
- 接下來它會看到關鍵字
return,然後期望下一個標記是一個整數值,因為 main 返回一個整數,它會找到 0,這是一個整數。 - 然後下一個符號是分號,所以這是語句的結束。
- 下一個標記是右大括號,所以這是函式的結束。並且沒有更多標記了,所以如果語法分析器沒有在程式碼中發現任何錯誤,它會將標記傳送給編譯器,以便程式可以被轉換為機器語言。
這只是語法分析的一個簡單檢視,真正的語法分析器並不真正以這種方式工作,但其思想是相同的。
以下是一些語法分析器會查詢的關鍵字,以確保您沒有將它們用作識別符號名稱,或者瞭解您正在定義的變數型別或正在使用的函式,這些函式包含在 C++ 語言中。
編譯速度
[edit | edit source]有幾個因素決定了編譯的速度,例如
- 硬體
- 資源(慢速 CPU、記憶體不足,甚至慢速 HDD 都會有影響)
- 軟體
- 編譯器本身,新的總是更好,但可能取決於您希望專案移植到什麼程度。
- 為程式選擇的方案(物件依賴結構、包含)也會起作用。
經驗表明,如果您遇到編譯速度慢的問題,您嘗試編譯的程式設計很差,花點時間構建自己的程式碼以最大程度地減少更改後的重新編譯。大型專案總是編譯速度更慢。使用預編譯標頭檔案和外部標頭檔案保護。我們將在本書的 最佳化 部分討論減少編譯時間的方法。
哪裡可以獲得編譯器
[edit | edit source]在選擇編譯器時,您必須考慮您的系統作業系統、個人偏好以及您在使用它時可以獲得的文件。
如果您沒有、不想或不需要在機器上安裝編譯器,可以使用 http://ideone.com(或 http://codepad.org,但您需要更改程式碼以不需要互動式輸入)上的 WEB 免費編譯器。如果您需要,您總是可以在本地獲得一個。
有很多編譯器,甚至更多的 IDE 可用,有些是免費的和開源的。IDE 通常會將所需的編譯器包含在安裝中(GCC 是最常見的)。
GCC
[edit | edit source]GCC 是最成熟、最相容的 C++ 編譯器之一,也稱為 GNU 編譯器集合。它是一套由自由軟體基金會開發的免費編譯器,理查德·斯托曼是主要架構師之一。
網際網路上有許多不同的預編譯 GCC 二進位制檔案;下面列出了一些流行的選擇(以及詳細的安裝步驟)。您可以在 GCC 網站上輕鬆找到有關如何在其他作業系統上執行此操作的資訊。
IDE(整合開發環境)
[edit | edit source]
整合開發環境 是一種軟體開發系統,它通常將編輯器、編譯器和偵錯程式整合在一個一起分發的整合包中。有些 IDE 需要使用者自己進行元件整合,而另一些則將 IDE 稱為他們用於程式設計的一組獨立工具。
一個好的 IDE 是一個允許程式設計師使用它來抽象和加速一些更常見任務,同時在閱讀和管理程式碼方面提供一些幫助的 IDE。除了編譯器之外,C++ 標準對不同的實現沒有控制。大多數 IDE 都是面向視覺的,尤其是新的 IDE,它們將提供圖形偵錯程式和其他視覺輔助工具,但有些人仍然喜歡像 Vim 或 Emacs 這樣的強大文字編輯器提供的視覺簡潔。
在選擇 IDE 時,請記住,您也在投入時間來精通它的使用。完整性、穩定性和跨作業系統的可移植性將非常重要。
對於 Microsoft Windows,您還有 Microsoft Visual Studio Community(最新版本 2019),目前可以免費獲得,並且包含大多數功能。它包含一個 C++ 編譯器,可以從命令列或提供的 IDE 中使用。
在本書的 附錄 B:外部參考 中,您將找到對可以使用的其他免費編譯器和 IDE 的引用。
在 Windows 上
[edit | edit source]Cygwin
- 轉到 http://www.cygwin.com 並單擊頁面右上角的“立即安裝 Cygwin”按鈕。
- 在彈出的視窗中單擊“執行”,然後多次單擊“下一步”,接受所有預設設定。
- 當該視窗彈出時,選擇任何下載站點(“ftp.easynet.be”等);按“下一步”,Cygwin 安裝程式應開始下載。
- 當“選擇包”窗口出現時,向下滾動到“Devel”標題,並單擊它旁邊的“+”。在現在顯示的包列表中,向下滾動並找到“gcc-c++”包;這是編譯器。單擊“跳過”一詞一次,它應該更改為類似“3.4”之類的數字(版本號),並且“gcc-core”以及現在將要下載的幾個其他必需包旁邊會出現一個“X”。
- 單擊“下一步”,編譯器以及 Cygwin 工具應開始下載;這可能需要一段時間。在等待的同時,轉到 http://www.crimsoneditor.com 並下載該免費程式設計師編輯器;它功能強大,但對於初學者來說易於使用。
- Cygwin 下載完成後,點選“下一步”等完成安裝,雙擊桌面上的 Cygwin 圖示啟動 Cygwin “命令提示符”。 您的主目錄將自動設定在 Cygwin 資料夾中,現在應該在“C:\cygwin”中(Cygwin 資料夾在某種程度上就像您 Windows 機器上的一個小 Unix/Linux 計算機——當然不是技術上,但把它想象成那樣可能會有所幫助)。
- 在 Cygwin 提示符下輸入“g++”並按“回車”; 如果出現“g++: no input files”或類似的資訊,則表示您已成功安裝了 gcc C++ 編譯器到您的計算機上(恭喜——您還剛剛收到您的第一個錯誤資訊!)。
MinGW + DevCpp-IDE
- 前往 http://www.bloodshed.net/devcpp.html ,(嚴重過時,上次更新於 2005 年)(http://orwelldevcpp.blogspot.com/) (Updated Branch project) 選擇您想要的版本(最終向下滾動),然後點選相應的下載連結! 對於最新版本,您將被重定向到 http://www.bloodshed.net/dev/devcpp.html
- 向下滾動以閱讀許可證,然後到下載連結。 下載包含 Mingw/GCC 的版本。 它比自己組裝要容易得多。 經過短暫的延遲(只有幾天),您將始終獲得與 devcpp IDE 打包的最新版本的 MinGW。 它與手動下載所需模組完全相同。
- 您將獲得一個可執行檔案,可以在任何 WinNT 版本的使用者級別下執行。 但是,如果您希望將其設定為所有使用者,則需要管理員許可權。 它將安裝 devcpp 和 mingw 到您想要的資料夾中。
- 啟動 IDE 並體驗您的第一個專案!
您會發現它與 MSVC 大致相似,包括選單和按鈕放置。 當然,如果您熟悉前者,許多方面會有所不同,但只需點選幾下即可讓您的第一個程式執行。
DJGPP
- 前往 Delorie 軟體 並下載 GNU C++ 編譯器和其他必要的工具。 該網站提供了一個 Zip Picker,以幫助您確定需要哪些檔案,該檔案可在主頁面上獲得。
- 使用 unzip32 或其他提取工具將檔案放置到您選擇的目錄中(例如 C:\DJGPP)。
- 設定環境變數以配置 DJGPP 進行編譯,方法是將行新增到 autoexec.bat 或自定義批處理檔案中
set PATH=C:\DJGPP\BIN;%PATH%set DJGPP=C:\DJGPP\DJGPP.ENV
- 如果您執行的是 MS-DOS 或 Windows 3.1,則需要在 config.sys 中新增幾行,如果它們不存在。
shell=c:\dos\command.com c:\dos /e:2048 /pfiles=40fcbs=40,0
注意: DJGPP 下的 GNU C++ 編譯器名為 gpp。
- 對於 Gentoo,GCC C++ 是系統核心的一部分(因為 Gentoo 中的所有內容都是編譯的)
- 對於 Redhat,獲取一個 gcc-c++ RPM,例如使用 Rpmfind,然後使用以下命令安裝(作為 root):rpm -ivh gcc-c++-version-release.arch.rpm
- 對於 Fedora,使用以下命令安裝 GCC C++ 編譯器(作為 root):dnf install gcc-c++
- 對於 Mandrake,使用以下命令安裝 GCC C++ 編譯器(作為 root):urpmi gcc-c++
- 對於 Debian,使用以下命令安裝 GCC C++ 編譯器(作為 root):apt-get install g++
- 對於 Ubuntu,使用以下命令安裝 GCC C++ 編譯器:sudo apt-get install g++
- 對於 openSUSE,使用以下命令安裝 GCC C++ 編譯器(作為 root):zypper in gcc-c++
- 如果您無法成為 root 使用者,請從 [1] 獲取 tarball 並按照其中的說明在您的主目錄中編譯和安裝。
Xcode(Apple 的 OSX 和 iOS 的 IDE)v4.1 以上版本使用 Clang [2],它是 GCC 編譯器的免費開源替代方案,與 GCC 大致相容(甚至使用相同的命令列引數)。 IDE 還捆綁了 GCC C++ 編譯器的舊版本。 它可以透過與 Linux 相同的方式從終端呼叫,但也可以在 XCode 的其中一個專案中進行編譯。
