序號 | 過程名 | 過程 | 代碼 |
---|---|---|---|
1 | 預處理preprocessing | 將.c中的頭文件,宏定義展開及替換,生成.i文件 | gcc -E -o hello.i hello.c |
2 | 編譯compilation | 將預處理之后的.i文件生成匯編代碼.s文件 | gcc -S -o hello.s hello.i |
3 | 匯編assembly | 把.s匯編文件生成.o目標文件 | gcc -c -o hello.o hello.s |
4 | 鏈接linking | 將匯編生成的.o obj文件,系統(tǒng)庫的obj文件,庫文件鏈接起來,最終生成可以在特定平臺運行的可執(zhí)行程序 | gcc -o hello hello.o |
定義一個宏 #define P 3.14
終止一個宏 #undef P (想在中間終止宏,后面遇到宏不可用)
不帶參宏 #define P 3.1415
帶參宏 #define S(a,b) (a)*(b) (宏的形參沒有類型)
宏是在預編譯的時候進行替換
宏的作用范圍:從定義的地方到本文末尾
帶參宏和帶參函數的區(qū)別
1.帶參宏被調用多少次就會展開多少次,執(zhí)行代碼的時候沒有函數調用過程,不需要壓棧彈棧。
所以帶參宏,是浪費了空間,因為被展開多次,節(jié)省了時間。
2.帶參函數,代碼只有一次,存在代碼段,調用的時候去代碼段取指令,調用的時候要壓棧彈棧。有個調用的過程,帶參函數是浪費了時間,節(jié)省了空間。
3.帶參函數的形參是有類型的,帶參宏的形參是沒有類型名
四、選擇性編譯(1) ifdef
如果在當前.c上定義過AA這個宏,就編譯代碼段1 ,否則編譯代碼段2
#ifdef AA
代碼段1
#else
代碼段2
#endif
(2) ifndef
如果在當前.c上沒有定義過BB這個宏,就編譯代碼段1 ,否則編譯代碼段2
#ifndef BB
代碼段1
#else
代碼段2
#endif
一般用在#include"aa.h"中,避免頭文件重復包含。
在aa.h中
#ifndef __FUN_AA__
#define __FUN_AA__
extern int funaa*(int x, int y);
#endif
五、靜態(tài)庫與動態(tài)庫我們經常用到庫函數,比如printf,strcpy
實際上庫函數都是由編譯系統(tǒng)提供的,它會將庫函數的源碼對應的.c 編譯成庫文件,
我們的代碼中只需要調用這些庫函數所在的庫文件就可以了 (就是#include)。
1、什么是靜態(tài)、動態(tài)編譯?靜態(tài)編譯: 使用的是靜態(tài)庫文件進行編譯
gcc -static hello.c -o hello
要把靜態(tài)庫文件打包編譯到可執(zhí)行程序中
動態(tài)編譯: 使用的是動態(tài)庫文件進行編譯(默認)
gcc hello.c -o hello
不會把動態(tài)庫文件打包編譯到可執(zhí)行程序中,只是編譯鏈接關系
運行可執(zhí)行程序時需要依賴靜態(tài)庫
**靜態(tài)鏈接:** 是由編譯器在鏈接時將庫的內容加入到可執(zhí)行程序中的做法。
這里的庫指的是靜態(tài)鏈接庫 (windows下以.lib為后綴,linux下以.a為后綴)
**動態(tài)鏈接:** 把鏈接這個過程推遲到了運行時再進行,在可執(zhí)行文件裝載時或運行時,由操作系統(tǒng)的裝載程序加載庫。
這里的庫指的是動態(tài)鏈接庫(windows下以.dll為后綴,linux下以.so為后綴)
2、為什么要使用靜態(tài)、動態(tài)編譯?不想讓別人看見內部接口的實現(xiàn)細節(jié),只需要提供一個接口名和鏈接庫文件。
3、使用靜態(tài)編譯/動態(tài)編譯文件1: mylibguo.c 定義 max()方法
文件2: mylibguo.h 聲明 max()方法
文件3: myTest.c 主函數,調用max()方法
文件1 ? mylibguo.c
#includeint max(int a, int b)
{if(a >= b)
return a;
else
return b;
}
文件2 ? mylibguo.h
#ifndef __MAX_H__
#define __MAX_H__
extern int max(int a, int b);
#endif
文件3 ? myTest.c
#include#include "mylibguo.h"
int main()
{printf("this is main()\n");
int num = 0;
num = max(5, 9);
printf("In main(), num=%d\n",num);
return 0;
正常編譯
gcc myTest.c mylibguo.c -o myTest
./myTest
3.1、 使用靜態(tài)編譯(1)制作靜態(tài)庫 ? 將mylibguo.c打包成庫文件(.a)
gcc -c mylibguo.c -o mylibguo.o
ar rc libguo.a mylibguo.o
生成的庫文件需要以lib開頭, .a結尾【此處為 libguo.a 】
有了靜態(tài)庫文件后,編譯文件就不需要知道m(xù)ain函數中調用的接口的具體實現(xiàn)了【也就是不需要mylibguo.c】,只需要調用接口的聲明【mylibguo.h】和庫文件 libguo.a
(2)利用靜態(tài)庫編譯程序 ?
方法一: 庫文件和main文件在同一個目錄
gcc -static myTest.c libguo.a -o myTest
./myTest
結果:
this is main()
In main(), num=9
方法二: 可以指定頭文件及庫文件的路徑
把頭文件和庫文件移動至/home_local/tester/suki/normalTest/1128/guo目錄
pwd
/home_local/tester/suki/normalTest/1128
ll
total 24
drwxrwxr-x 2 tester tester 6 Nov 28 02:20 guo
-rw-rw-r-- 1 tester tester 1388 Nov 27 23:59 libguo.a
-rw-rw-r-- 1 tester tester 75 Nov 3 23:53 mylibguo.h
-rw-rw-r-- 1 tester tester 169 Nov 28 00:08 myTest.c
mv libguo.a mylibguo.h guo/
ll
total 16
drwxrwxr-x 2 tester tester 40 Nov 28 02:21 guo
drwxrwxr-x 2 tester tester 42 Nov 28 00:06 move
-rwxrwxr-x 1 tester tester 8632 Nov 28 00:10 myTest
-rw-rw-r-- 1 tester tester 169 Nov 28 00:08 myTest.c
gcc -static myTest.c -o myTest -L/home_local/tester/suki/normalTest/1128/guo -lguo -I /home_local/tester/suki/normalTest/1128/guo
./myTest
結果:
this is main()
In main(), num=9
-L 大寫L 庫文件的路徑
-l 小寫L 指定找哪個庫,只要寫庫文件名,lib后 .a前的部分
-I 大寫I 指定頭文件的路徑
方法三: 將庫文件和頭文件放在系統(tǒng)默認指定的路徑下
庫文件默認路徑是 /lib 或 /usr/lib
頭文件默認路徑是 /usr/include
sudo mv libguo.a /usr/lib
sudo mv mylibguo.h /usr/include
gcc -static myTest.c -o myTest -lguo
./myTest
3.2、 使用動態(tài)編譯(1)制作動態(tài)庫 ? 將mylibguo.c打包成庫文件(.so)
gcc -shared mylibguo.c -o libguo.so
生成的庫文件需要以lib開頭, .so結尾【此處為 libguo.so 】
有了動態(tài)庫文件后,編譯文件就不需要知道m(xù)ain函數中調用的接口的具體實現(xiàn)了【也就是不需要mylibguo.c】,只需要調用接口的聲明【mylibguo.h】和庫文件 libguo.so
(2)利用動態(tài)庫編譯程序 ?
方法一: 庫文件和main文件在同一個目錄
gcc myTest.c libguo.so -o myTest
A 可以看到已經生成了可執(zhí)行文件
ll
-rwxrwxr-x 1 tester tester 8600 Nov 28 19:01 myTest
B 執(zhí)行可執(zhí)行文件
發(fā)現(xiàn)在加載動態(tài)庫的時候出錯了
./myTest
./myTest: error while loading shared libraries: libguo.so: cannot open shared object file: No such file or directory
動態(tài)庫只是建立鏈接關系,可執(zhí)行程序運行的時候加載.so中的代碼后,才去執(zhí)行。執(zhí)行時還需要依賴動態(tài)庫,這個庫不是一個標準的C庫,并且還沒有放在默認指定的路徑下,所以在運行時系統(tǒng)還找不到,因此要添加環(huán)境變量,讓系統(tǒng)知道,這個庫在哪
export LD_LIBRARY_PATH=./:SLD_LIBRARY_PATH
執(zhí)行
./myTest
結果
this is main()
In main(), num=9
方法二: 頭文件及庫文件假設在 /home_local/tester/suki/normalTest/1129/guo 目錄
gcc myTest.c -o myTest -L/home_local/tester/suki/normalTest/1129/guo -lguo -I/home_local/tester/suki/normalTest/1129/guo
執(zhí)行,生成了myTest,說明編譯成功,但是運行時出錯
./myTest
./myTest: error while loading shared libraries: libguo.so: cannot open shared object file: No such file or directory
因為編譯時找到了庫函數,但是鏈接時找不到庫,
需要執(zhí)行以下操作,把鏈接庫目錄加入搜索路徑
export LD_LIBRARY_PATH=/home_local/tester/suki/normalTest/1129/guo:$LD_LIBRARY_PATH
執(zhí)行
./myTest
結果
this is main()
In main(), num=9
方法三: 庫文件和main文件均在系統(tǒng)路徑下
cp libguo.so /usr/lib
cp mylibguo.h /usr/include
gcc myTest.c -o myTest -lguo
./myTest
我們前面的靜態(tài)庫也放在/usr/lib下了,那么連接的到底是靜態(tài)庫還是動態(tài)庫呢
當靜態(tài)庫與動態(tài)庫重名時,系統(tǒng)會優(yōu)先連接動態(tài)庫,或者通過加上-static來連接靜態(tài)庫。
你是否還在尋找穩(wěn)定的海外服務器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調度確保服務器高可用性,企業(yè)級服務器適合批量采購,新人活動首月15元起,快前往官網查看詳情吧