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 巨集有時因為操作符優先順序問題會導致計算邏輯出錯 而函式會將值...