目錄
前言
?gcc/g++介紹
gcc/g++的編譯指令(以gcc為例)
?編輯?gcc選項
預處理(進行宏替換)
?編譯(生成匯編)
匯編(生成機器可識別代碼)
?鏈接(生成可執行文件或庫文件)
?函數庫
概念
?動態庫和靜態庫
?
?前言
編譯器的處理過程:
- 預處理(進行宏替換)
- 編譯(生成匯編)
- 匯編(生成機器可識別代碼)
- 鏈接(生成可執行文件或庫文件)
?更加詳細的介紹,可以參照這篇博客:C語言翻譯環境:預編譯+編譯+匯編+鏈接詳解-CSDN博客
??gcc/g++介紹
GCC(GNU Compiler Collection)是一個由GNU項目開發的編譯器套件,它包括了用于多種編程語言的編譯器,如C、C++、Fortran、Ada、Go等。GCC是一個開源的工具集,可在多個平臺上運行,支持多種操作系統和架構。它是許多操作系統的默認編譯器,也是許多開源項目的首選編譯工具。
在GCC中,gcc和g++分別是用于編譯C和C++代碼的編譯器。
-
gcc:
- 功能:gcc是GCC套件中用于編譯C語言代碼的編譯器。它將C源代碼編譯成目標代碼,并調用GCC的后端來生成可執行文件或庫文件。
- 特點:gcc支持多種C語言標準,如ANSI C(C89/C90)、C99和C11。開發人員可以使用gcc來編譯符合不同C語言標準的代碼,并生成與目標平臺兼容的可執行文件。
- 選項:gcc提供了豐富的編譯選項和優化選項,開發人員可以通過這些選項來控制編譯過程中的各種行為,如優化級別、調試信息、警告設置等。
-
g++:
- 功能:g++是GCC套件中用于編譯C++代碼的編譯器。它是gcc的C++編譯器前端,通過調用GCC的后端來生成目標代碼。
- 特點:g++支持多種C++標準,如C++98、C++11、C++14、C++17等。開發人員可以使用g++來編譯符合不同C++標準的代碼,并生成高效的可執行文件或庫文件。
- 選項:與gcc類似,g++也提供了豐富的編譯選項和優化選項,可以幫助開發人員優化編譯過程并生成高效的目標代碼。
除了編譯器之外,GCC還包括了一些其他工具,如預處理器、匯編器、鏈接器等,可以幫助開發人員完成整個編譯過程。
?gcc/g++的編譯指令(以gcc為例)
首先可以查看一下自己的Linux上gcc的版本,確認是否有gcc編譯器。
gcc --version
??gcc選項
- -E 只激活預處理,這個不生成文件,你需要把它重定向到一個輸出文件里面
- -S 編譯到匯編語言不進行匯編和鏈接
- -c 編譯到目標代碼
- -o 文件輸出到 文件
- -static 此選項對生成的文件采用靜態鏈接
- -g 生成調試信息。GNU 調試器可利用該信息。
- -shared 此選項將盡量使用動態庫,所以生成文件比較小,但是需要系統由動態庫.
- -O0,-O1,-O2,-O3 編譯器的優化選項的4個級別,-O0表示沒有優化,-O1為缺省值,-O3優化級別最高
- -w 不生成任何警告信息。
- -Wall 生成所有警告信息
?預處理(進行宏替換)
- 預處理功能主要包括宏定義,文件包含,條件編譯,去注釋等。
- 預處理指令可以讓編譯器進行完預處理過程后,就停止,生成目標文件。
- 實例: gcc -E test.c -o test.i
- 選項“-E”,該選項的作用是讓 gcc 在預處理結束后停止編譯過程。
- 選項“-o”是指目標文件,-o filename 可以指定生成的可執行文件的名稱,“.i”文件為已經過預處理的C原始程序。
??編譯(生成匯編)
- 在這個階段中,gcc 首先要檢查代碼的規范性、是否有語法錯誤等,以確定代碼的實際要做的工作,在檢查無誤后,gcc 把代碼翻譯成匯編語言。
- 用戶可以使用 “-S” 選項來進行查看,該選項只進行編譯而不進行匯編,生成匯編代碼。
- 實例: gcc -S test.i -o test.s
?匯編(生成機器可識別代碼)
- 匯編階段是把編譯階段生成的“.s”文件轉成目標文件
- 使用選項“-c”就可看到匯編代碼已轉化為“.o”的二進制目標代碼了
- 實例: gcc -c test.s -o test.o
??鏈接(生成可執行文件或庫文件)
- 在成功編譯之后,就進入了鏈接階段。
- 實例: gcc test.o -o test.exe
?上述的四個指令,實際上在使用時都被壓縮成了一條指令,直接編譯:
gcc test.c -o test
??函數庫
?概念
函數庫(Library)是一種預先編寫好的、可重用的代碼集合,其中包含了一系列函數、類或其他程序組件,用于執行特定的任務或提供特定的功能。函數庫通常以文件或模塊的形式存在,可以在程序中引用和調用其中的函數來完成相應的操作。
比如我們的C程序中,并沒有定義“printf”的函數實現,且在預編譯中包含的“stdio.h”中也只有該函數的聲明,而沒有定義函數的實現,那我們為什么可以使用這個函數呢?
實際上,系統把這些函數實現都被做到名為 libc.so.6 的庫文件中去了,在沒有特別指定時,gcc 會到系統默認的搜索路徑“/usr/lib”下進行查找,也就是鏈接到 libc.so.6 庫函數中去,這樣就能實現函數“printf”了,而這也就是鏈接的作用。
??動態庫和靜態庫
-
靜態庫(Static Library):
- 靜態庫在編譯時被鏈接到可執行文件中,編譯后的可執行文件包含了靜態庫中的代碼。
- 每個使用了靜態庫的可執行文件都會包含一份靜態庫的副本,因此可執行文件體積較大。
- 靜態庫的代碼在編譯時被復制到可執行文件中,程序運行時不需要外部庫文件。
- 靜態庫的文件擴展名通常為
.lib
(Windows)或.a
(Unix/Linux)。
-
動態庫(Dynamic Library):
- 動態庫在程序運行時才加載到內存中,可執行文件只包含對動態庫的引用。
- 多個程序可以共享一份動態庫,減少內存占用和磁盤空間。
- 動態庫的代碼在程序運行時動態加載,可能會造成一定的性能損失。
- 動態庫的文件擴展名通常為
.dll
(Windows)或.so
(Unix/Linux)。
gcc的默認鏈接方式是鏈接動態庫,我們可以手動修改為鏈接靜態庫:
gcc -static test.c -o test-static
可以發現通過鏈接靜態庫生成的可執行程序的大小遠遠大于通過鏈接動態庫生成的可執行程序的大小。
gcc默認生成的二進制程序,是動態鏈接的,這點可以通過 file 命令驗證。
file+filename//查看文件類型
____________________
?感謝你的閱讀,希望本文能夠對你有所幫助。如果你喜歡我的內容,記得點贊關注收藏我的博客,我會繼續分享更多的內容。?
?