C語言編譯連線過程和巨集

2021-07-24 07:31:07 字數 3308 閱讀 1031

c語言**到二進位制**中間的四個轉換:

1.預處理(巨集替換、取注釋、標頭檔案展開、條件編譯)

對應的linux指令(gcc -e test.c -o test.i)//e預處理指令,在預處理之後停止,生成test.i檔案

2.編譯 (c語言**   轉換為 彙編**)

gcc -s test.i -o test.s)//s編譯指令,在編譯之後停止,生成test.s檔案

3.彙編 (彙編**   轉換為 二進位制**)

gcc -c test.s -o test.o)//c彙編指令,在彙編之後停止,生成test.o檔案

4.鏈結 (將不同部分的**和資料蒐集組合成乙個單一檔案的過程)

gcc test.o -o mytest)//鏈結指令,在鏈結之後停止,生成可執行文)

巨集

1.什麼是巨集?

#define機制包括了乙個規定,允許把引數替換到文字中,這種實現通常稱為巨集或者巨集定義

ansi 標準定義了如下幾個巨集

_line_ 表示正在編譯的檔案行號 

_fele_ 表示正在編譯的檔案名字

_date_  表示正在編譯時刻的日期字串

_time

_  表示編譯時刻的時間字串

_stdc_  表示該檔案是不是定義成標準的c程式,其值為1,否則未定義

2.#define替換

在程式展開#define定義和巨集的幾個步驟

1.呼叫巨集時,檢查引數本身是不是乙個巨集,如果是#define

定義的符號,替換它

2.替換文字插入到原來位置,對於巨集,引數名被它們的值替換

3.最後在進行掃瞄,看是否還有#define定義的符號,如果有替換它

例:

#include

#define m 10                   

#define sum(x) ((x)*(x)+(m)) 

int main()

在預處理時候a=sum(m)先被替換成a=sum(10)

a=sum(10)

在被替換成

a=((10)*(10)+(m))

最後進行掃瞄發現還有被#define定義

的符號m,則在一次進行替換 

a=((10)*(10)+(10))

在linux下生成進行完成預處理的文字

3.在定義巨集函式時的注意事項

1.每個實參例項應該被小括號括起來

例:a.#define sqrt(x) x*x

當你sqrt(4+1)這樣呼叫時,它會被替換成4+1*4+1==9,顯然這個結果是不符合預期的

所以你應該這樣定義

#define sqrt(x) (x)*(x),

當然這樣也是不完美的!

b. #define sum(x) (x)+(x)

當你2*

sum(5)

這樣呼叫時,它會被替換成2*(5)+(5)==15,這樣得到乙個不符合預期的結果

所以應該更加小心的定義它

#define sum(x) ((x)+(x))

和 #define sqrt(x) ((x)*(x))

2.用結構封裝語句序列並確保其正確

例:#include

#define fun() fun1();fun2()

#define fun1() printf("hello,")

#define fun2() printf("world\n")

int main()              

int main()

} 結果:

hello,

world    

world

為什麼有差異呢?

看看預處理之後的結果

可以清楚地看出,與處理之後的結果與我們預想的邏輯並不是很相符

因為在定義巨集函式時不能判斷使用者的使用環境,所以我們採用do-while-zero

結構進行封裝

我們把第一句巨集定義經行處理  #define fun() dowhile(0)

在預處理之後我們可以看到這樣的結果

這個結果就符合我們的邏輯預期。

4. 巨集引數插入字串常量的方法

1.臨近字串的連線特性

#define m 9

#define print (format,value)\

printf("the value is "format"\n",value)

print("%d",m);

結果:the value is 9

2.使用"#"運算子進行處理

#define m 9

#define print(format,value) \

printf("the value of "#value" is "format"\n",value)

print("%d",m);

結果:the value of m is 9

"#"用於函式巨集的替換部分,可以將乙個巨集引數轉換成乙個字串

3."##"它把它兩邊的符號連線成乙個符號

#include

#define m 9

#define n 10

#define mn 20

#define print() printf("%d\n", m##n)

int main()

結果 : 20

在預處理時m##n連線在一塊成為mn,mn又是乙個被定義的巨集,值為20

5.巨集與函式的比較

#define巨集

函式

**長度

每次使用時,進行**替換。**出現在程式中,導致程式長度大幅增長

每次使用時 

執行速度

快 存在函式呼叫和返回時的額外開銷

引數求值

引數每次用於巨集定義,他們都將重新求值。

引數只在呼叫前求值一次

引數型別

與型別無關

與型別有關

操作符優先順序

對於巨集函式中的引數求值應該非常小心,除非加上括號,否則會因為優先順序的原因產生不可預料的結果

函式引數只是在呼叫的時候求值一次,它的結果傳遞給函式,表示式的結果更容易預料

c語言編譯 鏈結過程

c語言的編譯鏈結過程 把c程式 源 轉換成可以在機器上執行的程式 可執行 需要進行編譯和鏈結的過程。1 編譯 主要包含兩個過程 1 預處理 巨集定義 檔案包含 條件編譯。在正式開始編譯之前根據預處理命令來修改原始檔的內容 2 編譯 優化 通過詞法分析和語法分析將指令翻譯成彙編 2 彙編 把組合語言 ...

C語言編譯和鏈結過程簡介

一 編譯過程簡介 編譯過程可以分為4部分內容組成 預處理器 編譯器 彙編器 鏈結器 1 預處理器 1 處理所有的注釋,以空格代替 2 講所有的 define刪除,並且展開所有的巨集定義 3 處理條件編譯指令 if,ifdef elif,else endif 4 處理 include,展開檔案包含 5...

巨集和函式的區別以及C語言的編譯鏈結過程

巨集和函式的區別大致可分為以下五點 1 巨集是完全替換,插入到程式中,會增加 的長度 而函式 是只出現在乙個地方,使用時呼叫即可。2 巨集的執行速度相比函式更快一些,因為在預編譯階段都已完成 函式則因為需要呼叫以及返回而需要額外時間。3 巨集有時因為操作符優先順序問題會導致計算邏輯出錯 而函式會將值...