懷化seo推廣國內(nèi)好的seo
預(yù)處理、動(dòng)態(tài)庫、靜態(tài)庫
1. 聲明與定義分離
一個(gè)源文件對(duì)應(yīng)一個(gè)頭文件
注意:
- 頭文件名以
.h
作為后綴頭文件名
要與對(duì)應(yīng)的原文件名
一致
例:
源文件:01_code.c
#include <stdio.h>
int num01 = 10;
int num02 = 20;
void add(int a, int b)
{int sum = a + b;printf("%d + %d = %d\n", a, b, sum);
}void mul(int a, int b)
{int mul = a + b;printf("%d + %d = %d\n", a, b, mul);
}
頭文件:01_code.h
extern int num01;
extern int num02;
extern void add(int, int);
extern void mul(int, int);
測試文件:test.c
#include <stdio.h>
#include "01_code.h"int main(int argc, char const *argv[])
{printf("num01 = %d\n", num01);printf("num02 = %d\n", num02);add(10, 20);mul(10, 20);return 0;
}
編譯:
命令:
gcc test.c 01_code.c
./a.out
輸出:
num01 = 10 num02 = 20 10 + 20 = 30 10 + 20 = 30
2. 預(yù)處理
2.1 c語言編譯過程
gcc -E hello.c -o hello.i 1、預(yù)處理
gcc -S hello.i –o hello.s 2、編譯
gcc -c hello.s -o hello.o 3、匯編
gcc hello.o -o hello_elf 4、鏈接
1、預(yù)編譯
- 將
.c
中的頭文件展開
、宏展開
生成
的文件是.i
文件2、編譯
- 將預(yù)處理之后的
.i
文件生成.s
匯編文件3、匯編
- 將
.s
匯編文件 生成.o
文件4、鏈接
- 將
.o
文件 鏈接成目標(biāo)文件(即可執(zhí)行文件)
預(yù)編譯包含
展開頭文件
定義頭文件
選擇性編譯注意:預(yù)編譯的內(nèi)容以 # 開頭
2.2 include
作用:展開頭文件
語法:
#include <>
用
尖括號(hào)
包含的頭文件, 在 系統(tǒng)指定的路徑下 找頭文件#:表示預(yù)編譯
#include ""
用
雙引號(hào)
包含頭文件,先在當(dāng)前目錄下找 頭文件,找不到,再到系統(tǒng)指定的路徑下找
注意:
1、include 經(jīng)常用來包含頭文件,可以包含
.c
文件,但是大家不要包含.c
因?yàn)?include 包含的文件會(huì)在預(yù)編譯被展開,如果一個(gè).c 被包含多次,展開多次,會(huì)導(dǎo)致函數(shù)重復(fù)定義。所以不要包含.c 文件2、預(yù)處理只是對(duì) include 等預(yù)處理操作進(jìn)行處理,并
不會(huì)進(jìn)行語法檢查
,這個(gè)階段有語法錯(cuò)誤也不會(huì)報(bào)錯(cuò),第二個(gè)階段即編譯階段才進(jìn)行語法檢查
。
例:
#include "01_code.h"//等價(jià)于 下面, 即在源文件中展開下面代碼extern int num01;
extern int num02;
extern void add(int, int);
extern void mul(int, int);
2.2 宏:define
作用:在預(yù)處理 處理定義 類似于
變量
或函數(shù)
的東西。即:宏是在預(yù)編譯的時(shí)候進(jìn)行替換 。
2.2.1 不帶參宏
語法:
#define 宏名 值 //宏定義#undef 宏名 //取消宏定義
注意:
1、如果定義該類型的宏(不帶參的宏),
值可以省略
2、無需分號(hào)結(jié)束
3、在 宏定義后,取消定義前 可以使用
4、只能在
當(dāng)前文件中
使用
例:
#include <stdio.h>
#define PI 3.14
int main(int argc, char const *argv[])
{printf("pi = %f\n", PI);
#undef PI //取消宏定義return 0;
}
2.2.2 帶參宏
語法:
#define 宏名(形參) 體
注意:
1、形參沒有數(shù)據(jù)類型
2、
帶參宏
與帶參函數(shù)
的區(qū)別
宏:在
預(yù)編譯時(shí)
對(duì)其進(jìn)行 替換,如果一個(gè)文件中多次使用宏
,那意味著要替換多次
,此時(shí)就需占用內(nèi)存,所以占據(jù)的內(nèi)存多
- 產(chǎn)生的預(yù)編譯時(shí)期
- 占內(nèi)存多
- 速度快
函數(shù):在程序運(yùn)行時(shí)在代碼區(qū)存儲(chǔ)一份,每次調(diào)用該函數(shù)都需在代碼區(qū)尋找,將其放入棧內(nèi)存中(壓棧),當(dāng)函數(shù)執(zhí)行完畢后,從棧中移除(彈棧)
- 產(chǎn)生在運(yùn)行時(shí)
- 占內(nèi)存少
例:
#include <stdio.h>
#define ADD(a, b) a+b
#define MUL(a, b) a*b
#define MUL02(a, b) (a)*(b)
int main(int argc, char const *argv[])
{int sum = ADD(20, 30);printf("sum=%d\n", sum);int mul = MUL(20, 30);printf("mul=%d\n", mul);int mul02 = MUL(20+10, 30+10); //20 + 10 * 30 +10printf("mul=%d\n", mul02);int mul03 = MUL02(20+10, 30+10); //(20 + 10) * (30 + 10)printf("mul=%d\n", mul03);return 0;
}
2.2.3 小結(jié)
宏就是在
預(yù)編譯時(shí)期
對(duì)其進(jìn)行替換
不帶參宏替換的是一個(gè)值
帶參宏替換的是一段代碼
2.3 選擇性編譯
作用:選擇代碼是否被編譯
語法:
例1:判斷存在
優(yōu)點(diǎn):節(jié)省內(nèi)存,只加載需要的部分
#include <stdio.h>int main(int argc, char const *argv[])
{#ifdef XXXprintf("有定義宏名為XXX的宏\n");#elseprintf("沒定義宏XXX\n");#endifreturn 0;
}
編譯時(shí)定義宏:
例2:判斷不存在,和頭文件配合使用,防止多次引用頭文件
#include <stdio.h>
#include "04_test.h"
#include "04_test.h"
int main(int argc, char const *argv[])
{#ifndef YYYprintf("1111\n");#elseprintf("2222\n");#endifreturn 0;
}
頭文件:04_test.h
#ifndef TEST
#define TEST
extern int num;
//...
#endif
#ifndef 使用含義:
1、
第一次
引用頭文件,沒有定義TEST宏
,然后定義,再寫頭文件內(nèi)容;2、假如
再次引用
頭文件時(shí),第一次已經(jīng)定義過TEST宏
了,所以直接結(jié)束
,啥也不干。
源碼寫法:
例3:判斷是否成立
#include <stdio.h>
int main(int argc, char const *argv[])
{#if ScORE > 85printf("A\n");#elif ScORE > 70printf("B\n");#elif ScORE >= 60printf("c\n");#elseprintf("D\n");#endifreturn 0;
}
3. 庫
概念:庫也叫代碼庫,可以把一個(gè)些目標(biāo)文件合并在一起方便使用。
3.1 分類
靜態(tài)庫
動(dòng)態(tài)庫
靜態(tài)庫、動(dòng)態(tài)庫的區(qū)別:
注意:
- 程序中引入的文件在動(dòng)態(tài)庫與靜態(tài)庫同時(shí)存在兩份
- 靜態(tài)編譯程序引入靜態(tài)庫中的該文件
- 動(dòng)態(tài)編譯程序引入動(dòng)態(tài)庫中的該文件
3.2 編譯命令
動(dòng)態(tài)編譯:
gcc 源文件名 -o 生成的可執(zhí)行文件名
靜態(tài)編譯:
gcc -static 源文件名 -o 生成的可執(zhí)行文件名
3.3 靜態(tài)庫
3.3.1 制作
gcc -c 源文件名.c -o 生成的二進(jìn)制文件名.o
ar rc lib靜態(tài)庫名稱.a 生成的二進(jìn)制文件名.o
注意:
靜態(tài)庫起名
的時(shí)候必須 以lib 開頭
以.a
結(jié)尾
步驟:
-
新建文件夾:
06_code
-
源文件:
myfun.c
#include <stdio.h>void add(int a, int b) {printf("my_sum = %d\n", (a+b)); }void mul(int a, int b) {printf("my_mul = %d\n", (a*b)); }
-
頭文件:
myfun.h
extern void add(int a, int b); extern void mul(int a, int b);
-
制作
3.3.2 使用
情況1:使用靜態(tài)庫的文件與靜態(tài)庫 在同一文件夾下
命令:
gcc 源文件名 靜態(tài)庫名稱 -o 生成的可執(zhí)行文件名
測試文件:test01.c
#include <stdio.h>
#include "myfun.h" //可以不寫,但是會(huì)報(bào)警告
int main(int argc, char const *argv[])
{add(10, 3);return 0;
}
編譯:
情況2:使用靜態(tài)庫的文件與靜態(tài)庫 不在同一文件夾下
注意:
為了讓靜態(tài)庫文件與其對(duì)應(yīng)的頭文件和使用靜態(tài)庫文件不在同一文件夾下,所以
創(chuàng)建includes與libs文件夾
includes文件用于存儲(chǔ)頭文件
libs文件夾存儲(chǔ)靜態(tài)庫文件
mkdir includes mkdir libs mv myfun.h includes/ mv libmyfun.a libs/
參數(shù)
-L 引用的靜態(tài)庫所在的路徑 -l 靜態(tài)庫名, 去掉lib與.a -I 頭文件所在路徑
命令
gcc 源文件名 -L 靜態(tài)庫所在的路徑 -l 靜態(tài)庫名 -I 頭文件所在路徑 -o 生成的可執(zhí)行文件名
情況3:靜態(tài)庫文件與對(duì)應(yīng)的頭文件 在系統(tǒng)文件夾下
系統(tǒng)庫路徑:
/usr/include 存儲(chǔ)頭文件 /usr/lib 或 /lib 存儲(chǔ)庫文件
注意:
# 為了讓靜態(tài)庫文件與其對(duì)應(yīng)的頭文件和系統(tǒng)文件夾下,所以需要移動(dòng) sudo mv includes/myfun.h /usr/include sudo mv libs/libmyfun.a /usr/lib
命令:
gcc 源文件名 -l 靜態(tài)庫名 -o 生成的可執(zhí)行文件名
3.4 動(dòng)態(tài)庫
3.4.1 制作
命令:
gcc -shared 源文件名 -o 生成的動(dòng)態(tài)庫文件名.so
3.4.2 使用
情況1:使用動(dòng)態(tài)庫的文件與動(dòng)態(tài)庫在同一文件夾下
命令:
gcc 源文件名 動(dòng)態(tài)庫名稱 -o 生成的可執(zhí)行文件名
情況2:使用動(dòng)態(tài)庫的文件與動(dòng)態(tài)庫不在同一文件夾下
命令:
gcc 源文件名 -L 動(dòng)態(tài)庫所在路徑 -l 動(dòng)態(tài)庫名稱 -I 頭文件所在路徑
注意:
- 動(dòng)態(tài)庫名需要去掉前面的
lib
與后面.so
情況3:靜態(tài)庫文件與對(duì)應(yīng)的頭文件在系統(tǒng)文件夾下
命令:
gcc 源文件名 -l 靜態(tài)庫名 -o 生成的可執(zhí)行文件名