Table of Contents
知識簡介
編譯 :把高級語言書寫的代碼轉換爲機器可識別的機器指令。編譯高級語言後生成的指令雖然可被機器識別,但是還不能被執行。編譯時,編譯器檢查高級語言的語法、函數與變量的聲明是否正確。只有所有的語法正確、相關變量定義正確編譯器就可以編譯出中間目標文件。通常,一個高級語言的源文件都可對應一個目標文件。目標文件在Linux 中默認後綴爲“.o”(如“foo.c”的目標文件爲“foo.o”)。
鏈接 :將多.o 文件,或者.o 文件和庫文件鏈接成爲可被操作系統執行的可執行程序(Linux 環境下,可執行文件的格式爲“ELF”格式)。鏈接器不檢查函數所在的源文件,只檢查所有.o 文件中的定義的符號。將.o 文件中使用的函數和其它.o 或者庫文件中的相關符號進行合併,對所有文件中的符號進行重新安排(重定位),並鏈接系統相關文件(程序啓動文件等)最終生成可執行程序。鏈接過程使用 GNU 的“ld”工具。
靜態庫 :又稱爲文檔文件(Archive File)。它是多個.o 文件的集合。Linux 中靜態庫文件的後綴爲“.a”。靜態庫中的各個成員(.o 文件)沒有特殊的存在格式,僅僅是一個.o 文件的集合。使用“ar”工具維護和管理靜態庫。
共享庫 :也是多個.o 文件的集合,但是這些.o 文件時有編譯器按照一種特殊的方式生成(Linux 中,共享庫文件格式通常爲“ELF”格式。共享庫已經具備了可執行條件)。模塊中各個成員的地址(變量引用和函數調用)都是相對地址。使用此共享庫的程序在運行時,共享庫被動態加載到內存並和主程序在內存中進行連接。多個可執行程序可共享庫文件的代碼段(多個程序可以共享的使用庫中的某一個模塊,共享代碼,不共享數據)。另外共享庫的成員對象可被執行(由 libdl.so 提供支持)。
gcc
Linux下的c編譯器中,gcc是功能最強大、使用最廣泛的軟件。
gcc是(GNU Cmpiler Collection的簡稱),它是GNU項目中符合ANSI C標準的編譯系統,能夠編譯用C、C++和Object C等語言編寫的程序。
gcc不僅功能十分強大,結構也異常靈活。它可以通過不同的前端模塊來支持各種語言,如Java、Fortran、Pascal、Modula-3和Ada等。
gcc是可以在多種硬體平臺上編譯出可執行程序的超級編譯器,其執行效率與一般的編譯器相比,平均效率要高20%~30%。
gcc支持編譯的後綴名:
後綴名 | 對應語言 | 後綴名 | 對應語言 |
.c | C原始程序 | .ii | 已經經過預處理的C++原始程序 |
.C | C++原始程序 | .s | 彙編語言原始程序 |
.cc | C++原始程序 | .S | 彙編語言原始程序 |
.cxx | C++原始程序 | .h | 預處理文件(頭文件) |
.m | Objective-C原始程序 | .o | 目標文件 |
.i | 已經經過預處理的c原始程序 | .a/.so | 編譯後的庫文件 |
gcc指令的一般格式爲:
gcc [參數] 要編譯的文件 [參數] [目標文件]
gcc 1-2.c -o 1-2
gcc編譯流程:
- 編輯源碼程序代碼
- 預處理階段:
gcc 1-3.c -o 1-3.i -E
- 編譯階段:
gcc 1-3.i -o 1-3.s -S
- 彙編階段
gcc 1-3.s -o 1-3.o -c
- 鏈接階段:完成鏈接後,gcc就可以生成可執行程序文件
注意:gcc在編譯的時候默認使用動態鏈接庫,編譯鏈接時並不把庫文件的代碼加入到可執行文件中,而是在程序執行的時候動態加載鏈接庫,這樣可以節省系統開銷。
總體參數
參數 | 含義 | 參數 | 含義 |
-c |
只是編譯不鏈接 |
-v | 顯示gcc的版本信息 |
-S | 只是編譯不彙編,生成彙編代碼 | -I dir | 在頭文件的搜索路徑中添加dir目錄 |
-E | 只進行預編譯 | -L dir | 在庫文件的搜索路徑列表中添加dir目錄 |
-g | 在可執行程序中包含調試信息 | -static | 鏈接靜態庫 |
-o file | 把輸出文件輸出到file中 | -l libra | 連接名爲library的庫文件 |
當頭文件與gcc不在同一目錄下要用-I dir編譯,它是指頭文件,而添加庫文件時需用-L dir參數。
Linux下的庫文件命名時有一個規定:必須以l、i、b三個字母開頭,因此,在用“-l”指定鏈接庫文件時可以省去l、i、b三個字母。也就是說“-llibsunq”有時候寫成“-lsunq”。
gcc的常用警告和出錯參數
參數 | 含義 |
-ansi | 支持符合ANSI的c程序 |
-pedantic | 允許發出ANSI c標準所列的全部警告信息 |
-pendantic-error | 允許發出ANSI c標準所列的全部錯誤信息 |
-w | 關閉所有警告 |
-Wall | 允許發出gcc提供的所有有用的告警信息 |
-werror | 把所有的告警信息轉化爲錯誤信息,並在告警發生時終止編譯 |
步驟 2:關閉所有告警
gcc 1-7.c –o 1-7 –w
步驟 3:顯示不符合ANSI c標準語法的告警信息
gcc 1-7.c –o 1-7 –ansi
步驟 4: 允許發出ANSI c標準所列的全部警告信息
gcc 1-7.c –o 1-7 –pedantic
步驟 5:允許發出gcc提供的所有有用的告警信息
gcc 1-7.c –o 1-7 –Wall
優化參數
代碼優化指的是編譯器通過分析源代碼,找出其中尚未達到最優的部分,然後對其重新進行組合,目的是改善程序的執行性能。
gcc提供的代碼優化功能非常強大,它通過編譯參數“-On”來控制優化代碼的生成,其中n是一個代表優化級別的整數。
通常來說,數字越大優化的等級越高,同時也就意味着程序的運行速度越快。
gcc 1-8.c –o 1-8 –O2
優化雖然能夠給程序帶來更好的執行性能,但在一些場合中應該避免優化代碼。
- 程序開發的時候。
- 資源受限的時候。
- 跟蹤調試的時候。
gdb
Linux下的gdb調試器,是一款GNU組織開發併發布的UNIX/Linux下的程序調試工具。它沒有圖形化的友好界面,但功能強大。
在進行應用程序的調試之前,要注意的是gdb進行調試的是可執行文件,而不是如“.c”這樣的源代碼文件。因此,需要先通過gcc編譯生成可執行文件才能用gdb進行調試。
gcc 1-9.c –o 1-9 –g
gdb 1-9
常用的gdb命令
命令格式 | 作用 |
list<行號>|<函數名> | 查看指定位置的程序源代碼 |
break 行號|函數名<條件表達式> | 設置斷點 |
info break | 顯示斷點信息 |
run | 運行程序 |
print 表達式|變量 | 查看程序運行時對應表達式和變量的值 |
next | 單步恢復程序運行,但不進入函數調用 |
step | 單步恢復程序運行,且進入函數調用 |
continue | 繼續執行函數,直到函數結束或遇到新的斷點 |
用gdb調試程序
- 查看源文件
在gdb中輸入“l”(list)就可以查看程序源代碼,一次顯示10行;
- 設置斷點
在gdb中設置斷點命令是“b”(break),後面跟行號或者函數名。
如:(gdb) b 10
- 查看斷點信息
用命令“info b”(info break)查看斷點信息。
注意:gdb在一個程序中可以設置多個斷點,有多個斷點中斷時,“Num”處顯示斷點序號。
- 運行程序:輸入“r”(run)開始運行程序。
注意:gdb默認從第一行開始運行,如果要從程序中指定行開始運行,只需輸入“r”+行號。
- 查看變量值
程序運行到斷點處會自動暫停,輸入“p 變量名”.
調試程序時,可能需要修改變量值,程序運行到斷點處時,輸入“set 變量=設定值”,例如給變量“a2” 賦值11,輸入“set a2=11”。
gdb在顯示變量值時都會在對應值前加“$n”標記,它是當前變量值的引用標記,以後想再引用此變量,可以直接使用“$n”,提高了調試效率
注意:查看變量值,不能在程序結束後。
- 單步運行
在斷點處輸入 “n”(next)或者“s”(step) 。它們之間的區別在於:若有函數調用時,“s”會進入該函數而“n”不會進入該函數。
- 繼續運行程序
輸入“c”(continue)命令恢復程序的正常運行,把剩餘的程序執行完,並顯示執行結果。
- 退出gdb環境:輸入“q”(quit)命令。