C語言的編譯過程可分為四個階段:
對源程式中的僞指令(即以#開頭的指令)和特殊符号進行處理的過程。
僞指令包括:1)宏定義指令;
2)條件編譯指令;
3)頭檔案包含指令;
編譯就是将源程式轉換為計算機可以執行的二進制代碼。
說明:
在Linux下,目标檔案的預設字尾為.o
編譯程式将通過詞法分析和文法分析,将其翻譯成為等價的彙編代碼。
在使用gcc進行編譯時,預設情況下,不輸出這個彙編代碼的檔案。如果需要,可以在編譯時指定-S選項。這樣,就會輸出同名的彙編語言檔案。
彙編的過程實際上是将彙編語言代碼翻譯成機器語言的過程。
産生一個擴充名為.o的目标檔案。
目标代碼不能直接執行,要想将目标代碼變成可執行程式,還需要進行連結操作。才會生成真正可以執行的可執行程式。
連結操作最重要的步驟就是将函數庫中相應的代碼組合到目标檔案中。
gcc可以針對支援不同的源程式檔案進行不同的處理,檔案格式以檔案的字尾來識别。
檔案名字尾
檔案類型
.c
C源檔案
.C .cpp .cc .c++ .cxx
C++源檔案
.h
頭檔案
.i
預處理後的C源檔案
.s
彙程式設計式檔案
.o
目标檔案
.a
靜态連結庫
.so
動态連結庫
gcc(GNU Compiler Collection)
在Linux平台上最常用的C語言編譯系統是gcc,它是GNU項目中符合ANSI C标準的編譯系統。
gcc的使用格式:
gcc [options][filenames]
說明:當不用任何選項時,gcc将會生成一個名為a.out的可執行檔案。
例子:在linux上編譯一個c程式(檔案名為hello.c ;執行gcc hello.c)。
#include <stdio.h>
int main()
{
printf("hello world.\n");
return 0;
}
運作編譯好的可執行c檔案指令是./a.out
源代碼轉換為彙編語言(在編譯時選擇-S選項,可以看到生成的彙編代碼.s檔案)
彙編代碼(.s)轉換為目标代碼(.o)
将目标代碼與各庫函數進行連結并重定位,生成可執行程式。
選項
說明
-D name
定義一個宏name,并可以指定值
-I dir
指定頭檔案的路徑dir。先在指定的路徑中搜尋要包含的頭檔案,若找不到,則在标準路徑(/usr/include,/usr/lib及目前工作目錄)上搜尋。
-E
隻對檔案進行預處理,不進行編譯、彙編、連結,生成的結果送标準輸出
即:隻運作C預編譯器
-o file
将輸出寫到指定的檔案file中
即:産生目标(.i 、.s 、 .o 、可執行檔案等)
例子:使用 -I選項包含儲存在非标準位置中的頭檔案。
# gcc -I/usr/openwin/include file.c
例子:使用-D選項定義宏,其作用等價于在源檔案中使用宏定義指令。
main()
printf("display -D variable %s\n",DOPTION);
printf("hello,everybody!!\n");
# gcc -D DOPTION='"testing -D"' hello.c
-o file1 file2
将檔案file2編譯成可執行檔案file1。
如果未使用該選項,則可執行檔案放在a.out中
-S
隻進行編譯,不進行彙編,生成彙編代碼檔案擴充名為.s
即:告訴編譯器産生彙編語言檔案後停止編譯
-c
隻把源檔案編譯成目标代碼.o,不進行彙編、連結。
用于實作對源檔案的分别編譯
-g
在目标代碼中加入供調試程式gdb使用的附加資訊
-v
顯示gcc版本
-Wall
顯示警告資訊
例子:在gcc中使用-W控制警告資訊。
# gcc -Wall -o hello1 hello1.c
例子:使用gcc的-g選項來産生調試符号,
# gcc -g -o test1 test1.c
例子:多檔案的編譯。
//meng1.c
int r;
printf("enter an integer,please!\n");
scanf("%d",&r);
square(r);
return 0;
//meng2.c
int square(int x)
printf("The square=%d\n",x*x);
return (x*x);
編譯方法一:
# gcc -c meng1.c
# gcc -c meng2.c
# gcc meng1.o meng2.o -o meng12
編譯方法二:
# gcc -o meng13 meng1.c meng2.c
方法二不産生中間目标檔案,直接生成一個可執行檔案,因而,程式内容稍有改動,就要重新編譯全部程式。
優化是編譯器的一部分,它可以檢查群組合編譯器生成的代碼,指出未達到最優的部分,并重新生成它們,進而使使用者編寫的程式更加完美且節省空間。
在gcc編譯器選項中,使用-O選項對代碼進行優化。
優化級别分3級,由高到低分别為:-O3、-O2、-O1,
優化程式選項
-O1(-O)
對編譯出的代碼進行優化
-O2
進行比-O高一級的優化
-O3
産生更進階别的優化
-O1(或-O)、-O2、-O3分别代表優化級别,數字越高,代表gcc的優化級别越高,高的優化級别代表着程式将運作的更快。
優化級别越高則程式量越大。
直接優化程式本身,性能的提高的變化更加明顯。
庫:是一組預先編譯好的函數集合。
标準庫檔案一般存儲在/lib和/usr/lib目錄中。
所有的庫名都以lib開頭。例如:libc.so(标準C語言函數庫)、libm.so(數學運算函數庫)
以.a結尾的是靜态庫;以.so結尾的庫是動态庫。
使用ar工具将目标檔案收集起來,放到一個歸檔檔案中。
連接配接程式選項
-L dir
将dir所指出的目錄加到“函數庫搜尋清單”中
-llib
連結lib庫
-I name
連接配接時,加載名字為name的函數庫。該庫位于系統預設的目錄或者由-L選項确定的目錄下。
實際的庫名是libname(字尾為.a或.so)
連結過程通常的形式如下:
gcc -o file file.o -L dirname -lxxx
-L:指定了連結時用到的庫檔案所在的目錄。
-lxxx:訓示連結的庫函數名為libxxx.a
例子:編譯産生可執行檔案hello,搜尋數學庫以解決問題。
# gcc -o hello hello.c /usr/lib/libm.a
或者
# gcc -o hello hello.c -lm
例子:建立一個小型庫
包含兩個函數pro1、pro2,然後在示例程式中調用其中一個函數。
/* pro1.c */
void pro1(int arg)
printf("hello:%d\n", arg);
/* pro2.c */
void pro2(char *arg)
printf("welcome to:%s", arg);
/* lib.h */
void pro1(int);
void pro2(char *);
/* program.c */
#include "lib.h"
pro2("Linux world.");
exit(0);