1. 程式人生 > >Linux下GCC使用入門

Linux下GCC使用入門

本文轉載自百度空間:http://hi.baidu.com/qds316/item/881b6bd97cfd2c30e2108f28

一、GCC簡介

通常所說的GCC是GUN CompilerCollection的簡稱,除了編譯程式之外,它還含其他相關工具,所以它能把易於人類使用的高階語言編寫的原始碼構建成計算機能夠直接執行的二進位制程式碼。GCC是Linux平臺下最常用的編譯程式,它是Linux平臺編譯器的事實標準。同時,在Linux平臺下的嵌入式開發領域,GCC也是用得最普遍的一種編譯器。GCC之所以被廣泛採用,是因為它能支援各種不同的目標體系結構。例如,它既支援基於宿主的開發(簡單講就是要為某平臺編譯程式,就在該平臺上編譯),也支援交叉編譯(即在A平臺上編譯的程式是供平臺B使用的)。目前,GCC支援的體系結構有四十餘種,常見的有X86系列、Arm、PowerPC等。同時,GCC還能執行在不同的作業系統上,如Linux、Solaris、Windows。

除了上面講的之外,GCC除了支援C語言外,還支援多種其他語言,例如C++、Ada、Java、Objective-C、FORTRAN、Pascal等。

本系列文章中,我們不僅介紹GCC的基本功能,還涉及到一些諸如優化之類的高階功能。另外,我們還考察GCC的一些映像操作工具,如size和objcopy等,這將在後續的文章中加以介紹。

二、程式的編譯過程

對於GUN編譯器來說,程式的編譯要經歷預處理、編譯、彙編、連線四個階段。     

從功能上分,預處理、編譯、彙編是三個不同的階段,但GCC的實際操作上,它可以把這三個步驟合併為一個步驟來執行。下面我們以C語言為例來談一下不同階段的輸入和輸出情況。

在預處理階段,輸入的是C語言的原始檔,通常為*.c。它們通常帶有.h之類標頭檔案的包含檔案。這個階段主要處理原始檔中的#ifdef、#include和#define命令。該階段會生成一箇中間檔案*.i,但實際工作中通常不用專門生成這種檔案,因為基本上用不到;若非要生成這種檔案不可,可以利用下面的示例命令:

gcc -E test.c -o test.i

在編譯階段,輸入的是中間檔案*.i,編譯後生成組合語言檔案*.s 。這個階段對應的GCC命令如下所示:

gcc -S test.i -o test.s

在彙編階段,將輸入的彙編檔案*.s轉換成機器語言*.o。這個階段對應的GCC命令如下所示:

gcc -c test.s -o test.o

最後,在連線階段將輸入的機器程式碼檔案*.s(與其它的機器程式碼檔案和庫檔案)彙集成一個可執行的二進位制程式碼檔案。這一步驟,可以利用下面的示例命令完成:

gcc test.o -o test

上面介紹了GCC編譯過程的四個階段以及相應的命令。下面我們進一步介紹常用的GCC的模式。

三、GCC常用模式

這裡介紹GCC追常用的兩種模式:編譯模式和編譯連線模式。下面以一個例子來說明各種模式的使用方法。為簡單起見,假設我們全部的原始碼都在一個檔案test.c中,要想把這個原始檔直接編譯成可執行程式,可以使用以下命令:

$gcc -o test test.c

這裡test.c是原始檔,生成的可執行程式碼存放在一個名為test 的檔案中(該檔案是機器程式碼並且可執行)。-o 是生成可執行檔案的輸出選項。如果我們只想讓原始檔生成目標檔案(給檔案雖然也是機器程式碼但不可執行),可以使用標記-c ,詳細命令如下所示:

$gcc -c test.c

預設情況下,生成的目標檔案被命名為test.o,但我們也可以為輸出檔案指定名稱,如下所示:

$gcc -c test.c -o mytest.o

上面這條命令將編譯後的目標檔案命名為mytest.o,而不是預設的test.o。

迄今為止,我們談論的程式僅涉及到一個原始檔;現實中,一個程式的原始碼通常包含在多個原始檔之中,這該怎麼辦?沒關係,即使這樣,用GCC處理起來也並不複雜,見下例:該命令將同時編譯三個原始檔,即first.c、second.c和 third.c,然後將它們連線成一個可執行程式,名為test。

$gcc -o test first.c second.c third.c

需要注意的是,要生成可執行程式時,一個程式無論有有一個原始檔還是多個原始檔,所有被編譯和連線的原始檔中必須有且僅有一個main函式,因為main函式是該程式的入口點(換句話說,當系統呼叫該程式時,首先將控制權授予程式的main函式)。但如果僅僅是把原始檔編譯成目標檔案的時候,因為不會進行連線,所以main函式不是必需的。

四、常用選項

許多情況下,標頭檔案和原始檔會單獨存放在不同的目錄中。例如,假設存放原始檔的子目錄名為./src,而包含檔案則放在層次的其他目錄下,如./inc。當我們在./src 目錄下進行編譯工作時,如何告訴GCC到哪裡找標頭檔案呢?方法如下所示:

$gcc test.c -I../inc -o test

上面的命令告訴GCC包含檔案存放在./inc 目錄下,在當前目錄的上一級。如果在編譯時需要的包含檔案存放在多個目錄下,可以使用多個-I 來指定各個目錄:

$gcc test.c -I../inc -I../../inc2 -o test

這裡指出了另一個包含子目錄inc2,較之前目錄它還要在再上兩級才能找到。

另外,我們還可以在編譯命令列中定義符號常量。為此,我們可以簡單的在命令列中使用-D選項即可,如下例所示:

$gcc -D TEST_CONFIGURATION test.c -o test

上面的命令與在原始檔中加入下列命令是等效的:

#define TEST_CONFIGURATION

在編譯命令列中定義符號常量的好處是,不必修改原始檔就能改變由符號常量控制的行為。

五、警告功能

當GCC在編譯過程中檢查出錯誤的話,它就會中止編譯;但檢測到警告時卻能繼續編譯生成可執行程式,因為警告只是針對程式結構的診斷資訊,它不能說明程式一定有錯誤,而是存在風險,或者可能存在錯誤。雖然GCC提供了非常豐富的警告,但前提是你已經啟用了它們,否則它不會報告這些檢測到的警告。

在眾多的警告選項之中,最常用的就是-Wall選項。該選項能發現程式中一系列的常見錯誤警告,該選項用法舉例如下:

$ gcc -Wall test.c -o test

該選項相當於同時使用了下列所有的選項:

◆unused-function:遇到僅宣告過但尚未定義的靜態函式時發出警告。
◆unused-label:遇到宣告過但不使用的標號的警告。
◆unused-parameter:從未用過的函式引數的警告。
◆unused-variable:在本地宣告但從未用過的變數的警告。
◆unused-value:僅計算但從未用過的值得警告。
◆Format:檢查對printf和scanf等函式的呼叫,確認各個引數型別和格式串中的一致。
◆implicit-int:警告沒有規定型別的宣告。
◆implicit-function-:在函式在未經宣告就使用時給予警告。
◆char-subscripts:警告把char型別作為陣列下標。這是常見錯誤,程式設計師經常忘記在某些機器上char有符號。
◆missing-braces:聚合初始化兩邊缺少大括號。
◆Parentheses:在某些情況下如果忽略了括號,編譯器就發出警告。
◆return-type:如果函式定義了返回型別,而預設型別是int型,編譯器就發出警告。同時警告那些不帶返回值的 return語句,如果他們所屬的函式並非void型別。
◆sequence-point:出現可疑的程式碼元素時,發出報警。
◆Switch:如果某條switch語句的引數屬於列舉型別,但是沒有對應的case語句使用列舉元素,編譯器就發出警告(在switch語句中使用default分支能夠防止這個警告)。超出列舉範圍的case語句同樣會導致這個警告。
◆strict-aliasing:對變數別名進行最嚴格的檢查。
◆unknown-pragmas:使用了不允許的#pragma。
◆Uninitialized:在初始化之前就使用自動變數。

需要注意的是,各警告選項既然能使之生效,當然也能使之關閉。比如假設我們想要使用-Wall來啟用個選項,同時又要關閉unused警告,利益通過下面的命令來達到目的:

$ gcc -Wall -Wno-unused test.c -o test

下面是使用-Wall選項的時候沒有生效的一些警告項:

◆cast-align:一旦某個指標型別強制轉換時,會導致目標所需的地址對齊邊界擴充套件,編譯器就發出警告。例如,某些機器上只能在2或4位元組邊界上訪問整數,如果在這種機型上把char *強制轉換成int *型別, 編譯器就發出警告。
◆sign-compare:將有符號型別和無符號型別資料進行比較時發出警告。
◆missing-prototypes :如果沒有預先宣告函式原形就定義了全域性函式,編譯器就發出警告。即使函式定義自身提供了函式原形也會產生這個警告。這樣做的目的是檢查沒有在標頭檔案中宣告的全域性函式。
◆Packed:當結構體帶有packed屬性但實際並沒有出現緊縮式給出警告。
◆Padded:如果結構體通過充填進行對齊則給出警告。
◆unreachable-code:如果發現從未執行的程式碼時給出警告。
◆Inline:如果某函式不能內嵌(inline),無論是宣告為inline或者是指定了-finline-functions 選項,編譯器都將發出警告。
◆disabled-optimization:當需要太長時間或過多資源而導致不能完成某項優化時給出警告。

上面是使用-Wall選項時沒有生效,但又比較常用的一些警告選項。本文中要介紹的最後一個常用警告選項是-Werror。使用該選項後,GCC發現可疑之處時不會簡單的發出警告就算完事,而是將警告作為一個錯誤而中斷編譯過程。該選項在希望得到高質量程式碼時非常有用。

六、小結

本文介紹了GCC的基本編譯過程和編譯模式,並詳細闡述了GCC的一些常用選項以及警告功能。這些是在利用GCC進行應用程式設計時最基本也最常用的一些內容,我們會在後續文章中繼續介紹GCC的除錯和優化技術。


相關推薦

LinuxGCC使用入門

本文轉載自百度空間:http://hi.baidu.com/qds316/item/881b6bd97cfd2c30e2108f28 一、GCC簡介 通常所說的GCC是GUN CompilerCollection的簡稱,除了編譯程式之外,它還含其他相關工具,所以它能把易於人

Linuxgrep入門

linux 運維 Linux下入門grep用法1.grep簡述及特點簡介:全局搜索正則表達式出來的行並打印 (Global search REgular expression and Print out the line),一種按照特定模式(pattern)的文本過濾工具模式:pattern,通過有正

LinuxGCC程式設計四個過程

在Linux下進行C語言程式設計,必然要採用GNU GCC來編譯C原始碼生成可執行程式。 一、GCC快速入門 Gcc指令的一般格式為:Gcc [選項] 要編譯的檔案 [選項] [目標檔案] 其中,目標檔案可預設,Gcc預設生成可執行的檔名為:編譯檔案.out 我們來看一下經典入門程式"Hello W

linuxgcc程式設計06-c語言參考手冊

一。 c語言標準庫介紹 二。c語言參考案例  巨集定義 巨集是在gcc編譯預處理階段就會執行的程式碼   //#pragma命令可以讓程式設計者讓編譯器執行某些事 #include <stdio.h> //包含io流的庫 標準的輸入和輸出 ""首先在

linuxgcc程式設計05-window開發工具安裝

一。 window下開發環境安裝   Unix下編譯通過的C程式碼,在win32下編譯是不能通過的 ,當然Unix 和win32的API都是符合標準C,也就是說,大多數函式呼叫在unix和win32下是相同的.但是,unix有自己一些獨特的API(如fork,spawn,s

linuxgcc程式設計04-cmake工程管理

一。cmake簡介  CMake是一個跨平臺的編譯、安裝、測試以及打包工具;CMake不直接編譯軟體,而是結合原生構建系統來構建軟體。    CMake配置檔案是CMakeList.txt檔案(每個原始碼資料夾下都要有一個),CMake根據配置檔案再生成Unix的Makef

Linuxgcc/g++、make和cmake的區別

文字程式到可執行檔案生成無論在什麼平臺大致分為以下幾個部分:    1.用編輯器編寫原始碼,如.c檔案。    2.用編譯器編譯程式碼生成目標檔案,如.o。    3.用連結器連線目的碼生成可執行檔案,如.exe。    Linux平臺下,.o檔案一般是通過編譯的但還未連結的

linuxgcc版本的升級和降級

                                       gcc版本的升降         在linux(Ubuntu)下做交叉編譯或者其他很多工時,經常需要改變編譯器的版本。這時候,我們可以通過下載編譯器的二進位制原始碼,自己編譯後安裝到系統。但是會

linuxgcc編譯 .c檔案生成動態連結庫 .so檔案,並測試呼叫該連結庫

簡單介紹:linux中so檔案為共享庫,和windows下dll相似;so可以共多個程序呼叫,不同程序呼叫同一個so檔案,所使用so檔案不同;so原檔案不需要main函式;例項,1.通過mysqlTest.c中的函式mysql(),生成一個libmysql.so連結庫#inc

ARP報文的傳送與接收(Linuxgcc編譯)

ARP報文的傳送與接收 這篇文章主要是關於ARP報文的傳送與接收,學習TCP/IP協議,還是多動手做一些測試對協議的理解比較深刻,所以自己寫了一份比較簡單的關於ARP的原始碼, 主要是起到記錄作用,方便以後回顧,當然,如果有大俠能提出問題,幫助我改進缺點是萬

Linuxgcc編譯生成動態連結庫*.so檔案並呼叫它

動態庫*.so在linux下用c和c++程式設計時經常會碰到,最近在網站找了幾篇文章介紹動態庫的編譯和連結,總算搞懂了這個之前一直不太瞭解得東東,這裡做個筆記,也為其它正為動態庫連結庫而苦惱的兄弟們提供一點幫助。1、動態庫的編譯下面通過一個例子來介紹如何生成一個動態庫。這裡

LinuxGCC 編譯時如何指定連結庫

-l引數和-L引數 -l引數就是用來指定程式要連結的庫,-l引數緊接著就是庫名,那麼庫名跟真正的庫檔名有什麼關係呢?就拿數學庫來說,他的庫名是m,他的庫檔名是libm.so,很容易看出,把庫檔名的頭lib和尾.so去掉就是庫名了。當我們自已要用到一個第三方提供的庫名字libtest.so,那麼我們只要把lib

Linuxgcc編譯器生成和使用靜態庫和動態庫學習筆記

我們通常把一些公用函式製作成函式庫,供其它程式使用。函式庫分為靜態庫和動態庫兩種。靜態庫在程式編譯時會被連結並拷貝到目的碼中,程式執行時將不再需要該靜態庫。動態庫在程式編譯時並不會被拷貝到目的碼中,而是在程式執行時才被載入,因此在程式執行時還需要動態庫存在。本質上說庫是一

Linuxgcc生成和使用靜態庫和動態庫詳解

一、基本概念 1.1什麼是庫 在windows平臺和linux平臺下都大量存在著庫。 本質上來說庫是一種可執行程式碼的二進位制形式,可以被作業系統載入記憶體執行。 由於windows和linux的平臺不同(主要是編譯器、彙編器和聯結器的不同),因此二者庫的二

linuxGCC編譯C程式(一)

GCC的"-lm"選項,它告訴GCC檢視系統提供的數學庫(libm)。因為Linux和UNIX的系統函式庫通常以"lib"為字首,所以我們假設它存在。真正的函式庫位置隨系統的不同而不同,但它一般會位於目錄/lib或/usr/lib中,在這些目錄中還有數以百計的其他必需的系統函式庫。 4. 共享函式庫與靜態函

linuxgcc命令筆記

首先介紹一下gcc各種引數的含義: -o:指定生成的輸出檔案; -E:僅執行編譯預處理; -S:將C程式碼轉換為彙編程式碼; -wall:顯示警告資訊; -c:僅執行編譯操作,不進行連線操作。

linux gcc的使用

 首先使用gcc要在linux環境下,我們可以使用真正的linux系統(不過這麼做可能有一些麻煩)或者使用一些windows下的虛擬軟體,可以使用虛擬機器搭建的linux環境,這樣可以很方便的進行linux開發。可以下載安裝一個虛擬機器軟體,方法很簡單和安裝普通軟體一樣。(g

LinuxOpencv入門程式設計一 (影象取反)

實現圖片畫素點的取反操作 -------------------------------------------------------------------------------------------------------------------- #includ

linuxgcc預設搜尋標頭檔案及庫檔案的路徑

linux下gcc預設搜尋標頭檔案及庫檔案的路徑 一、標頭檔案gcc 在編譯時如何去尋找所需要的標頭檔案:※所以header file的搜尋會從-I開始※然後找gcc的環境變數 C_INCLUDE_PATH,CPLUS_INCLUDE_PATH,OBJC_INCLUDE_

linuxgcc的使用方法

示例程式如下: 這個程式,一步到位的編譯指令是: 實質上,上述編譯過程是分為四個階段進行的,即預處理(也稱預編譯,Preprocessing)、編譯(Compilation)、彙編 (Assembly)和連線(Linking)。 可以輸出test.i檔案中存放著test.c經預處理之後的程式碼。開