GCC 指令詳解及動態庫、靜態庫的使用

GCC 指令詳解及動態庫、靜態庫的使用一、GCC1.1 GCC 介紹GCC 是 Linux 下的編譯工具集,是「GNU Compiler Collection」的縮寫,包含 gcc、g++ 等編譯器 。這個工具集不僅包含編譯器,還包含其他工具集,例如 ar、nm 等 。
GCC 工具集不僅能編譯 C/C++ 語言,其他例如 Objective-C、Pascal、Fortran、Java、Ada 等語言均能進行編譯 。GCC 還可以根據不同的硬件平臺進行編譯,即能進行交叉編譯,在 A 平臺上編譯 B 平臺的程序 , 支持常見的 X86、ARM、PowerPC、mips 等,以及 Linux、Windows 等軟件平臺 。
1.2 安裝 GCC首先,查看 gcc 是否安裝:
# 查看 gcc 版本$ gcc -v$ gcc --version# 查看 g++ 版本$ g++ -v$ g++ --version如果在輸入指令后可以獲取到 gcc 版本,那么就表明你的 Linux 中已經安裝了 gcc:

GCC 指令詳解及動態庫、靜態庫的使用

文章插圖
如果沒有安裝 , 則可按照如下方法安裝 gcc:
# centos$ sudo yum update# 更新本地的軟件下載列表, 得到最新的下載地址$ sudo yum install gcc g++ # 通過下載列表中提供的地址下載安裝包, 并安裝1.3 GCC 工作流程1.3.1 一般使用流程首先準備一個 C 語言代碼,并命名為 test.c:
#include <stdio.h>#define MAX 3int main(){int i;for (i = 1; i <= MAX; i++){printf("Hello World\n"); // 輸出 Hello World}return 0;}一般情況下,我們可以直接通過 $ gcc test.c -o test編譯 test.c,并通過$ ./test指令運行生成的可執行文件:
GCC 指令詳解及動態庫、靜態庫的使用

文章插圖
  • -o:output,是 gcc 編譯器的可選參數,用于指定輸出文件名及路徑,默認輸出到當前路徑下 。下圖展示了如何通過 -o 參數修改輸出路徑:
    GCC 指令詳解及動態庫、靜態庫的使用

    文章插圖
或者不使用 -o 參數,則生成一個默認名稱的可執行文件 a.out:
GCC 指令詳解及動態庫、靜態庫的使用

文章插圖
實際上 , GCC 編譯器在對程序進行編譯的時候 , 分為了四個步驟:
  1. 預處理(Pre-Processing):
    • 在這個階段主要做了三件事:展開頭文件 、宏替換 、去掉注釋行
    • 結果得到的還是一個 C 程序 , 通常是以 .i 作為文件擴展名
  2. 編譯(Compiling) :
    • 在這個階段中,gcc 首先要檢查代碼的規范性、是否有語法錯誤等,以確定代碼實際要做的工作
    • 在檢查無誤后,gcc 把代碼編譯成匯編代碼,得到一個以 .s 作為文件拓展名的匯編文件 。
  3. 匯編(Assembling):
    + 匯編階段是把編譯階段生成的 .s 文件轉化成目標文件+ 最終得到一個以 .o 結尾的二進制文件
  4. 鏈接(Linking):這個階段需要 GCC 調用鏈接器對程序需要調用的庫進行鏈接 , 最終得到一個可執行的二進制文件
而 GCC 的編譯器可以將這 4 個步驟合并成一個 , 這也就是為什么我們使用$ gcc test.c -o test就可以直接生成可執行文件 test 的原因 。下面我們對這 4 個步驟做個詳細的介紹 。
1.3.2 詳細的工作流程1.3.2.1 預處理# 通過添加參數 -E 生成預處理后的 C 文件 test.i# 必須通過 -o 參數指定輸出的文件名$ gcc -E test.c -o test.i讓我們來觀察一下 test.i 中的代碼內容(太長了,只觀察 main 函數中的替換情況):
int main(){int i;for (i = 1; i <= 3; i++){printf("Hello World\n");}return 0;}通過分析 test.i 可以發現:
  • 宏定義 MAX 被替換為了相應的值 3
  • 注釋「// 輸出 Hello World」也被去掉了
1.3.2.2 編譯# 通過添加參數 -S 將 test.i 轉換為匯編文件 test.s(默認生成 .s 文件)$ gcc -S test.i$ gcc -S test.i -o test.s # 寫法二1.3.2.3 匯編# 通過匯編得到二進制文件 test.o(默認生成 .o 文件,object)$ gcc -c test.s$ gcc -c test.s -o test.o # 寫法二1.3.2.4 鏈接# 通過鏈接得到可執行文件 test$ gcc test.o -o test在成功生成 test.o 文件后,就進入了鏈接階段 。在這里涉及到一個重要的概念:函數庫 。
在 test.c 的代碼中,我們通過print()函數打印 Hello World 語句;但是在這段程序中并沒有定義 printf 的函數實現,且在預編譯中包含進去的「stdio.h」中也只有該函數的聲明extern int printf (const char *__restrict __format, ...);,而沒有定義函數的實現,那么是在哪里實現的呢?

推薦閱讀