聲明與定義分離
聲明:將聲明單獨封裝成一個以.h為后綴名的頭文件
定義:將定義的變量,函數(shù),數(shù)組所在的源文件單獨封裝成一個.c文件。其實就是在源文件基礎上將定義過的所有東西的聲明分離出去就是了。
注意:1.聲明的.h文件名和.c結(jié)尾的源文件名要相同、
? ? ? ? ? ?2.一個源文件對應一個頭文件
1.預編譯
1.程序編譯
1.預編譯
? ? ? ? 展開頭文件
????????定義宏
? ? ? ? 選擇性編譯
? ? ? ? 注意:
????????????????展開頭文件必須以#開頭?
2.編譯
3.匯編
4.鏈接? ? ??
2.include
作用:展開頭文件
語法:
? ? ? ? #include<> 尖括號代表的頭文件是在系統(tǒng)指定文件中找該庫,具體在lib/或者在usr/lib文件中找
? ? ? ? #include""? "" 代表的是自己定義的庫,會先在當前目錄文件夾下找,如果找不到再在系統(tǒng)指定文件夾中找
注意:
1,include 經(jīng)常用來包含頭文件,可以包含 .c 文件,但是大家不要包含.c ,因為 include 包含的文
件會在預編譯被展開,如果一個.c 被包含多次,展開多次,會導致函數(shù)重復定義。所以不要包含.c 文件
2,預處理只是對 include 等預處理操作進行處理并不會進行語法檢查
這個階段有語法錯誤也不會報錯,第二個階段即編譯階段才進行語法檢查
3.宏(define)
1.定義不帶參的宏
? ? ? ? define pi(宏名)? 值
? ? ? ?注意:1.定義不帶參的宏,值可以不寫
? ? ? ? ? ? ? ? ? 2.不帶參的宏定義不要后面加分號
? ? ? ? ? ? ? ? ? 3.只能在當前文件中使用
? ? ? ? ? ? ? ? ? 4.在宏定義后,取消定義前使用
例子:? ? ??
????????#include <stdio.h>
????????#define PI 3.14
????????#define X
????????int main(int argc, char const *argv[])
????????{
????????printf("PI=%f\n",PI);
????????#undef PI //取消宏定義
????????//printf("PI=%f\n",PI);
????????return 0;
????????}
2.定義帶參的宏
? ? ? ? define 宏名(形參) a + b(體) ;
3.注意:
? ? ? ? 1.結(jié)尾要加分號
? ? ? ? 2.括號中可以加形參,后面運算表達式不能省
? ? ? ? 3.形參沒有數(shù)據(jù)類型
? ? ? ? 4.不止在當前文件中使用,可以在別的文件中使用
4.帶參和不帶參的宏的區(qū)別:
????????宏:在預編譯時對其進行替換,如果一個文件中多次使用宏,那意味著要替換多次,此時就需占用內(nèi)存,所以占據(jù)的內(nèi)存多
????????????????產(chǎn)生的預編譯時期
????????????????占內(nèi)存多
????????????????速度快
???????? ????????函數(shù):在程序運行時在代碼區(qū)存儲一份,每次調(diào)用該函數(shù)都需在代碼區(qū)尋找,將其放入棧內(nèi)存中(壓棧),當函數(shù)執(zhí)行完畢后,從棧中移除(彈棧)
? ? ? ? ? ? ? ? 產(chǎn)生在運行時
????????????????
? ? ? ? ? ? ? ? 占內(nèi)存少
5.#undef? ?宏名? ? ? ? ? //取消宏定義
6.總結(jié)
????????宏就是在預編譯時期對其進行替換
????????不帶參宏替換的是一個值
????????帶參宏替換的是一段代碼? ?
4.選擇性編譯
作用:選擇代碼是否被編譯
語法:

2.庫
作用:
? ? ? ? 也叫代碼庫,可以將一些目標文件放在一起合并方便使用
分類:
1.靜態(tài)庫
2.動態(tài)庫
動態(tài)庫與靜態(tài)庫的區(qū)別:

注意:
程序中引入的文件在動態(tài)庫與靜態(tài)庫同時存在兩份
靜態(tài)編譯程序引入靜態(tài)庫中的該文件
動態(tài)編譯程序引入動態(tài)庫中的該文件
編輯命令:
靜態(tài)庫:
? ? ? ? gcc? -static? 源文件名? - o? ?生成的可執(zhí)行文件名
動態(tài)庫:
? ? ? ? gcc? 源文件名? - o? ?生成的可執(zhí)行文件名
靜態(tài)庫:
制作:
????????gcc -c 源文件名.c -o 生成的二進制文件名.o
????????ar rc lib靜態(tài)庫名稱.a 生成的二進制文件名.o
????????注意:靜態(tài)庫起名的時候必須以 lib 開頭以 .a 結(jié)尾
使用:
????????情況1: 使用靜態(tài)庫的文件與靜態(tài)庫在同一文件夾下
????????????????命令:
????????????????gcc 源文件名 靜態(tài)庫名稱 -o 生成的可執(zhí)行文件名
????????????????
情況 2: 使用靜態(tài)庫的文件與靜態(tài)庫不在同一文件夾下 ? ? ? ? ? ? ? ??
????????????????注意:
????????????????為了讓靜態(tài)庫文件與其對應的頭文件和使用靜態(tài)庫文件不在同一文件夾下
????????????????所以創(chuàng)建includes與 libs 文件夾
????????????????includes文件用于存儲頭文件
????????????????libs文件夾存儲靜態(tài)庫文件
????????????????mkdir includes
????????????????mkdir libs
????????????????mv myfun.h includes/
????????????????mv libmyfun.a libs/
????????????????-L 引用的靜態(tài)庫所在的路徑
????????????????-l 靜態(tài)庫名, 不要 lib 與 .a
????????????????-I 頭文件所在路徑
???????????????? ????????????????命令:
????????????????????????gcc 源文件名 -L 靜態(tài)庫所在的路徑 -l 靜態(tài)庫名 -I 頭文件所在路徑 -o 生成的可執(zhí)行文件名
????????情況 3: 靜態(tài)庫文件與對應的頭文件在系統(tǒng)文件夾下
???????????????? ????????系統(tǒng)庫路徑:
????????????????/usr/include 存儲頭文件
????????????????/usr/lib 或 /lib 存儲庫文件
????????注意:
????????????????為了讓靜態(tài)庫文件與其對應的頭文件和系統(tǒng)文件夾下,所以需要移動
????????????????sudo mv includes/myfun.h /usr/include
????????????????sudo mv libs/libmyfun.a /usr/lib
????????命令:
????????????????gcc 源文件名 -l 靜態(tài)庫名 -o 生成的可執(zhí)行文件名
動態(tài)庫
制作:
? ? ? ? 命令:
????????????????gcc -shared 源文件名 -o 生成的動態(tài)庫文件名.so
使用:
????????情況1:使用動態(tài)庫的文件與動態(tài)庫在同一文件夾下
????????????????命令:
????????????????????????gcc 源文件名 動態(tài)庫名稱 -o 生成的可執(zhí)行文件名
????????情況2:使用靜態(tài)庫的文件與靜態(tài)庫不在同一文件夾下
????????????????命令:
????????????????????????gcc 源文件名 -L 動態(tài)庫所在路徑 -l 動態(tài)庫名稱 -I 頭文件所在路徑
????????????????注意:
????????????????????????動態(tài)庫名需要去掉前面的lib與后面.so
????????情況3:靜態(tài)庫文件與對應的頭文件在系統(tǒng)文件夾下
? ? ? ? ? ? ? ? 命令:
????????????????????????gcc 源文件名 -l 靜態(tài)庫名 -o 生成的可執(zhí)行文件名
注意:
????????運行中出現(xiàn)動態(tài)庫找不到問題,需要將動態(tài)庫所在目錄導入用戶環(huán)境變量

????????export LD_LIBRARY_PATH=庫文件所在路徑:$LD_LIBRARY_PATH
????????export LD_LIBRARY_PATH=./:$LD_LIBRARY_PATH
????????