Linux下的C語言開發環境
GCC編譯器介紹
目錄1.什麼是編譯器
編譯器是指從高階語言到低階語言的翻譯器,它是一種電腦程式,它可以將用某種程式語言寫成的原始碼(原始語言),轉換成另一種程式語言(目標語言),即計算機或者微型處理器能夠識別的二進位制機器程式碼(由0和1組成的序列)。
2.GCC編譯器
GCC編譯器是Linux下使用最廣泛的C/C++編譯器,大多數的Linux發行版本都預設安裝,它是一組編譯總工具的總成,軟體包裡包含了眾多的工具,按照型別可以分為:
1.C編譯器
2.C++編譯器
3.原始碼預處理程式
4.庫檔案
3.GCC編譯器的流程
GCC編譯器將原始碼檔案轉換為可執行檔案需要四個過程
1.預處理(完成巨集定義和include檔案展開等工作)
2.編譯(根據編譯引數進行不同程度的優化,編譯成彙編程式碼)
3.彙編(用匯編器把彙編程式碼進一步生成目的碼)
4.連結(用聯結器把生成的目的碼和系統或使用者提供的庫連線起來,生成可執行檔案)
GCC編譯器的使用
1.建立原始檔
首先,我們在目錄下新建一個名為ccc的資料夾。這個資料夾專門用來存放與C語言相關的檔案,例如原始檔、目標檔案、可執行檔案等,它專供我們學習使用。
接下來建立一個空白的 hello.c
cd ccc #進入ccc資料夾
touch hello.c #使用touch命令建立一個名為hello.c的空檔案
2.編輯原始檔
在Linux下,很多程式設計師都推崇使用Vim、Emacs、Nano等命令列模式的編輯器,它們功能強大(此前已經介紹了Vi編輯器的用法),但是它們並不容易上手,使用者需要記住很多命令和快捷鍵,所以需要一段時間的學習和適應。因此在這裡我使用了Gedit編輯器,Gedit是一款簡單實用的文字編輯器,比Vi容易上手,它和Windows下的編輯器沒有什麼區別。
Linux有的發行版可能沒有預設安裝Gedit,這裡給出安裝步驟:
sudo apt-add-repository ppa:ubuntu-on-rails/ppa #新增ubuntu的軟體源
sudo apt-get update #更新軟體列表
sudo apt-get install gedit-gmate #安裝
gedit hello.c
首先開啟首選項,根據自己的習慣進行編輯器的設定。
之後就可以編輯剛剛建立的原始檔了
我們在Gedit中輸入一段簡單的C語言程式碼:
按Ctrl+S儲存檔案,然後關閉Gedit視窗。
更多Gedit編輯器的使用方法見
3.GCC編譯流程的各項引數
gcc -E hello.c -o hello.i #預處理階段 -E,只執行到預編譯。直接輸出預編譯結果。
gcc -S hello.i -o hello.s #編譯階段 -S,只執行到原始碼到彙編程式碼的轉換,輸出彙編程式碼。
gcc -c hello.s -o hello.o #彙編階段 -c,只執行到編譯,輸出目標檔案。
gcc hello.o -o hello #連結階段 -o, 指定輸出檔名,可以配合以上三種標籤使用。
檔案型別
一談到檔案型別,大家就能想到Windows的檔案型別,比如.txt、.doc、.bat、.mp3、.exe等,根據檔案的字尾就能判斷檔案的型別。但在Linux系統中,一個檔案是否能被執行,和字尾名沒有太大的關係,與檔案的屬性有關,可執行檔案沒有統一的字尾,系統從檔案的屬性來區分可執行檔案和不可執行檔案。但是和計算機交流的畢竟還是程式設計師,對於一個光禿禿沒有後綴的檔案來說,沒辦法一眼看出到底是什麼檔案型別,那麼對於編譯過程其實會有一系列的約定俗成的檔案字尾,以方便程式設計師能夠快速知道這個檔案到底是什麼:gcc則通過後綴來區別輸入檔案的類別 。
以下是一些gcc輸入檔案字尾說明:
字尾 | 說明 |
---|---|
.c | C語言原始檔 |
.s | 組合語言的程式 |
.h | 源程式所包含的標頭檔案 |
.i | 預處理後的C程式 |
.ii | 預處理後的C++程式 |
.S | 預處理後的彙編程式 |
.o | 二進位制目標檔案(未經過連結,不能直接執行) |
.cpp .cc .cxx | C++源程式 |
.a | 有目標檔案構成的檔案庫檔案 |
.m | Objective-C源程式 |
雖然如此,通常在Linux中我們還是會以適當的副檔名來表示檔案的種類,下面列舉Linux中幾種常見的副檔名:
副檔名 | 說明 |
---|---|
.sh | 指令碼或批處理檔案,sh 命令呼叫預設 shell 並使用它的語法和標誌,因為批處理檔案為使用shell寫成的,所以副檔名就編成 .sh |
.tar .zip .tgz | 經過打包的壓縮檔案,由於壓縮軟體的不同而取不同的副檔名 |
.html .htm | HTML語法的網頁檔案,可以用網頁瀏覽器直接瀏覽 |
.php | PHP語法的網頁檔案,可以透過 client 端的瀏覽器來 server 端瀏覽 |
.txt | 純文字檔案 |
.so | 類庫檔案,在linux環境下,c++編譯得到庫檔案字尾包括.so |
.png .xpm .jpg | 影象檔案 |
4.演示
1.預處理之前編寫好的程式碼
開啟生成的.i檔案
預處理後可以看到,和之前的程式碼區別很大,增加了許多的內容,但是還依然是文字檔案可讀的。增加的這部分內容比如包含的標頭檔案之類的預處理內容
2.編譯預處理後的程式碼
處理完成後的檔案類似text
3.彙編編譯後的檔案
彙編完成後,可以看出,生成的檔案已經是一個二進位制檔案了,但這個檔案不具備執行的許可權
4.連結並執行
這時生成了一個可執行檔案,我們執行hello檔案,得到了想要的結果
當然,最簡單的生成可執行檔案的寫法為:
gcc hello.c
此時桌面上生成了一個名為a.out的檔案(gcc生成的可執行檔名預設為a.out),這就是最終生成的可執行檔案,這樣就一次完成了編譯和連結的全部過程
如果不想用預設的檔名,可以使用-o選項來自定義檔名,如
gcc hello.c -o b.out
因為Linux下可執行檔案的字尾僅僅是一種形式上的,所以可執行檔案也可以不帶字尾
gcc hello.c -o b
通過-o選項也可以將可執行檔案輸出到其他目錄,並不一定非得在當前目錄下,如:
gcc hello.c -o ./目錄名/b.out
gcc hello.c -o 目錄名/b.out
表示將可執行檔案輸出到當前目錄下的其他目錄,./表示當前目錄,如果不寫,預設也是當前目錄
注意:該目錄必須存在,如果不存在,gcc 命令不會自動建立目錄,而是丟擲一個錯誤。
如果要讓可執行程式包含除錯資訊,可以使用-g選項
gcc -g hello.c -o b.out
一般要除錯某個程式,為了能清晰地看到除錯的每一行程式碼、呼叫的堆疊資訊、變數名和函式名等資訊,需要除錯程式中包含除錯資訊。gcc中加上-g選項即可在編譯後的程式中保留除錯符號資訊,事實上,-g選項同樣適用於Cmake、Makefile等工具生成的Linux程式。
5.執行可執行程式
輸入
./a.out
./表示當前目錄,整條命令的意思是運行當前目錄下的 a.out 程式 ,按下回車鍵,程式就開始執行了,它會將輸出結果直接顯示在控制檯上。如果程式在其它目錄下,執行程式時還要帶上目錄的名字,如
./目錄名/a.out
目錄名/a.out
注意,如果程式沒有執行許可權,可以使用sudo命令來增加許可權,如
sudo chmod 777 a.out
Linux系統中,操作檔案或目錄的使用者有3種類型:檔案所有者、群組使用者、其他使用者。chmod命令最高位表示檔案所有著的許可權值,中間位表示群組使用者的許可權值,最低位表示其他使用者的許可權值
許可權數值 | 許可權 |
---|---|
4 | 當前使用者可以讀取檔案內容和瀏覽目錄 |
2 | 當前使用者可以修改檔案內容,改變目錄或目錄內檔案 |
1 | 當前使用者可以進入目錄,執行檔案 |
上述7=4+2+1,因此chmod 777命令可以給檔案增加執行許可權
偵錯程式GDB簡介
1.GDB是什麼?
gdb是GNU開源組織釋出的一個強大的Linux下的程式除錯工具,相比於VC等IDE除錯的優點是具有修復網路斷點以及恢復連結等功能,比BCB的圖形化偵錯程式有更強大的功能。
2.GDB的功能
一般來說,GDB主要幫助你完成下面四個方面的功能:
1、啟動你的程式,可以按照你的自定義的要求隨心所欲的執行程式。
2、可讓被除錯的程式在你所指定的調置的斷點處停住。(斷點可以是條件表示式)
3、當程式被停住時,可以檢查此時你的程式中所發生的事。
4、你可以改變你的程式,將一個BUG產生的影響修正從而測試其他BUG。
GDB的具體功能包括:
l 設定斷點
l 監視程式變數的值
l 程式的單步執行
l 顯示、修改變數的值
l 顯示、修改暫存器
l 檢視程式的堆疊情況
l 遠端除錯
3.GDB的執行
以之前編輯好的hello.c作為測試程式,首先生成可執行程式(為了產生除錯資訊,-g引數不能缺少)
輸入
gdb -v
檢視偵錯程式資訊,然後執行gdb
輸入l(list)命令顯示需要編譯除錯的源程式
設定斷點
GDB可以通過b(break)命令設定斷點,斷點的設定可以通過函式名、行號、檔名+函式名、檔名+行號以及偏移量、地址等進行設定,格式為:
b 函式名
b 行號
b 檔名:函式名
b 檔名:行號
b +偏移量
b -偏移量
b *地址
如圖斷點先下在第4行,執行後再通過b +1命令使斷點下在第6行
斷點設定時還可以條件斷住,格式為
break 斷點 if 條件。如
break sum if a==1
斷點還可以通過disable/enable臨時停用啟用,格式為
disable 斷點編號
disable 1 #停用斷點1
disable mem 記憶體區域
disable mem ox1151
enable 斷點編號
enable once 斷點編號(該斷點只啟用一次,程式執行到該斷點並暫停後,該斷點即被禁用)
enable mem 記憶體區域
刪除和檢視斷點
通過 info break 命令可以檢視設定的斷點列表
而斷點的刪除命令包括:
delete <斷點id>:刪除指定斷點
delete:刪除所有斷點
clear 函式名
clear 行號:刪除某一行所有斷點
clear 檔名:行號
clear 檔名:函式名
顯示變數
輸入命令“ print 變數 "可以檢視變數內容
如果需要一行監控多個變數,可以通過p {var1, var2, var3}
p {a,b,c}
如果要跟蹤變數自動顯示,可以使用display {var1, var2, var3}
display {m,n,f}
顯示暫存器
輸入命令” info reg (i r)”可以顯示暫存器內容
在暫存器名之前加$可以顯示暫存器內容,格式為
p/x $暫存器:十六進位制顯示暫存器內容
p $暫存器:顯示暫存器內容
用x命令可以顯示內容內容,格式為
“x/格式 地址” ,如
x $pc:顯示程式指標內容
執行
單步執行:包括next(n)命令和step(s)命令(兩者的區別是next遇到函式不會進入函式內部,step會執行到函式內部)
多步執行:使用continue和run命令,程式遇到斷點後暫停執行;如果沒有斷點,就會一直執行到結束
命令“continue 次數”可以實現使程式繼續執行一定次數的功能
監視點
要想找到變數在何處被改變,可以使用watch命令設定監視點watchpoint,格式為
watch <表示式>:表示式發生變化時暫停執行
watch a
awatch <表示式>:表示式被訪問、改變時暫停執行
waatch 2*a+4
rwatch <表示式>:表示式被訪問時暫停執行
應該注意的是,GDB不能監控一個常量,以下命令會使偵錯程式報錯
watch 1
其它命令
(gdb)set
:設定變數的值
set args arg1 arg2
(gdb)backtrace
:檢視函式的呼叫的棧幀和層級關係,簡寫bt
(gdb)info
:檢視函式內部區域性變數的數值,簡寫i
info args
(gdb)finish
:結束當前函式,返回到函式呼叫點
(gdb)undisplay
:取消追蹤觀察變數
undisplay i
(gdb)x
:檢視記憶體x/20xw 顯示20個單元,16進位制,4位元組每單元
(gdb)run argv[1] argv[2]
:除錯時命令列傳參
以上僅列舉了部分GDB常用的除錯命令,輸入
(gdb)help
可以檢視命令幫助,具體命令查詢在gdb中輸入help + 命令,簡寫h
筆者發現許多同學對gcc編譯器和gdb偵錯程式存在盲點,不知道二者具體的作用因此難以區分二者。gcc編譯器和gdb偵錯程式將成為我們未來學習中的重要工具,有助於提升我們的程式設計能力。謹希望本文能夠對大家有所幫助。
參考資料
[Linux GCC編譯器和GDB偵錯程式-簡書](Linux GCC編譯器和GDB偵錯程式 - 簡書 (jianshu.com))
其它文獻資料
本部落格僅作學習使用,如有侵權請聯絡作者