gcc編譯

fly1988happy發表於2015-07-29

基礎學習——gcc編譯

編譯——就是一個將原始碼翻譯成計算機處理器能識別的語言的過程。

gcc

gcc是linux系統中通用的c編譯器。

舉例說明:

test.c

#include <stdio.h>
int main(void){
    printf("Hello world\n");
    return 0;
}

編譯命令如下:

gcc test.c -o test

生成可執行檔案test。實質上,上述編譯過程是分為四個階段進行的,即預處理(也稱預編譯,Preprocessing)、編譯(Compilation)、彙編 (Assembly)和連線(Linking)。

1. 預編譯(預處理Preprocessing)

預處理功能主要包括 巨集定義、檔案包含、條件編譯 三個部分。
預處理過程讀入原始碼,檢查包含預處理指令的語句和巨集定義,並對原始碼進行相應的轉換。預處理過程還會刪除程式中的註釋和多餘的空白字元。

預處理指令 是指 以#開頭的程式碼行。#號必須是該行除了任何空白字元外的第一個字元。#後是指令關鍵字,在關鍵字和#號之間允許存在任意個數的空白字元。整行語句構成了一條預處理指令,該指令將在編譯器進行編譯之前對原始碼做某些轉換。

gcc -E test.c -o test.i  //可以檢視test.i,裡面存放著test.c經過預處理後的程式碼
或者
gcc -E test.c //直接在命令列視窗中輸出預處理後的程式碼
指令             用途
 #            空指令,無任何效果
 #include      包含一個原始碼檔案
 #define       定義巨集
 #undef        取消已定義的巨集
 #if          如果給定條件為真,則編譯下面程式碼
 #ifdef        如果巨集已經定義,則編譯下面程式碼
 #ifndef       如果巨集沒有定義,則編譯下面程式碼
 #elif         如果前面的#if給定條件不為真,當前條件為真,則編譯下面程式碼
 #endif        結束一個#if……#else條件編譯塊
 #error        停止編譯並顯示錯誤資訊
 #else         略
 #error        指令將使編譯器顯示一條錯誤資訊,然後停止編譯。
 #line         指令可以改變編譯器用來指出警告和錯誤資訊的檔案號和行號。
 #pragma       指令沒有正式的定義。編譯器可以自定義其用途。典型的用法是禁止或允許某 些煩人的警告資訊。

應用程式碼:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define SIX 6
#define SEVEN 7
#define Cube(x) (x)*(x)*(x)
#define VERSION "tzs"
#define PASTE(n) "最終勝利者是:"#n
#define NUM(a,b,c) a##b##c  // 其中 ##代表連線符,將a,b,c連線在一起
#define STR(a,b,c) a##b##c
#define DEBUG 1

int main()
{
    int i;
    i = SIX + SEVEN;
    printf("i = %d\n",i);
    i = (SIX * SEVEN);
    printf("i = %d\n",i);

    i = Cube(3);
    printf("i = %d\n",i);

    printf("%s",VERSION);
    printf("%s",PASTE(桃子));
    puts(PASTE(yy/));
    puts(PASTE(xx));

    printf("%d\n",NUM(1,2,3));
    //printf("%s\n",STR("aa","bb","cc"));

    #if DEBUG
        printf("Debugging\n");
        printf("Debugging2222\n");
    #endif
        printf("Running\n");
    #if defined DEBUG
        printf("yes\n");
    #endif
    #if !defined JJ
        printf("no JJ\n");
    #endif

}

參考:
http://blog.csdn.net/dotphoenix/article/details/4345174
http://www.cnblogs.com/ligongzi/archive/2012/08/24/2654732.html

2. 編譯(Compilation,編譯為彙編程式碼)

預處理之後,可以直接對生成的 test.i 進行編譯,生成彙編程式碼:

gcc -S test.i -o test.s

gcc的-S選項,表示在程式編譯期間,在生成彙編程式碼後,停止,-o輸出彙編程式碼檔案。

3. 彙編

對上面生成的彙編程式碼test.s,gas彙編器負責將其編譯為目標檔案。

gcc -c test.s -o test.o

gas彙編器是Linux平臺的標準彙編器,它是gcc所依賴的後臺彙編工具,通常包含在binutils軟體包中。gas使用標準的AT&T彙編語法。

參考:http://www.oschina.net/question/234345_43024

4. 連結

gcc聯結器是gas提供的,負責將程式的目標檔案與所需的所有附加的目標檔案連線起來,最終生成可執行檔案。附加的目標檔案包括靜態連線庫和動態連線庫。(連結器程式可以實現 編譯器的輸出 與 編譯程式所需要庫 之間的連結)
對於上面生成的test.o,將其與C標準輸入輸出庫進行連線,最終生成程式test。

gcc test.o -o test

執行./test即可輸出“Hello World!”。

庫是預編譯的目標檔案(object files)的集合,它們可被連結程式序。靜態庫以字尾為‘.a’的特殊的存檔檔案(archive file)儲存。

標準系統庫可在目錄 /usr/lib 與 /lib 中找到。比如,在類 Unix 系統中 C 語言的數學庫一般儲存為檔案 /usr/lib/libm.a。該庫中函式的原型宣告在標頭檔案 /usr/include/math.h 中。

C 標準庫本身儲存為 /usr/lib/libc.a,它包含 ANSI/ISO C 標準指定的函式,比如‘printf’。對每一個 C 程式來說,libc.a 都預設被連結。

參考:http://www.cnblogs.com/fly1988happy/archive/2012/03/31/2427274.html

相關文章