C語言程序的編譯與預處理詳解
一、程序的編譯
我們寫的源文件(*.c)是經(jīng)過怎樣的處理生產(chǎn)可執(zhí)行文件(*.exe)的呢?這種處理有兩個步驟—編譯和鏈接。源文件在編譯階段通過編譯器將每個源文件轉(zhuǎn)換為目標文件(這些文件是可執(zhí)行的機器指令),再通過鏈接器將其捆綁到一起,生成一個完整的可執(zhí)行程序。
1、 編譯階段
編譯階段可細分為3個階段:預處理(即預編譯)、編譯、匯編
預處理:主要進行頭文件的包含、處理預處理指令(如:#define定義符號的替換)、刪除注釋。此時(*.c)文件轉(zhuǎn)換為(*.i)文件。
編譯:主要進行語法分析、詞法分析、語義分析、符號匯總,此階段會將c語言代碼轉(zhuǎn)換為匯編代碼。此時(*.i)文件轉(zhuǎn)換為(*.s)文件。
匯編:此階段會形成符號表,將匯編代碼轉(zhuǎn)換為二進制指令(機器指令)。此時(*.s)文件轉(zhuǎn)換為(*.o)文件。
2、鏈接
此階段主要完成合并段表、符號表的合并和重定位工作,將(*.o)文件鏈接到一起生成可執(zhí)行文件。
二、預處理詳解
1、預定義符號
__FILE__ //進行編譯的源文件 __LINE__ //文件當前的行號 __DATE__ //文件被編譯的日期 __TIME__ //文件被編譯的時間 __STDC__ //如果編譯器遵循ANSI C,其值為1;如果不遵循,則編譯器不認識這個符號,是個未定義標識符,此時使用這個符號程序會報錯。該符號的作用是判斷編譯器是否遵循ANSI C。
下面為大家展示這些符號的作用。
執(zhí)行結(jié)果為:
2、#define定義的標識符
語法:
#define MAX 100
這句代碼的意思是數(shù)字“100”替換成符號MAX,例如:
#include <stdio.h> #define MAX 100 int main() { int i = 1 + MAX; printf("%d", i); return 0; }
結(jié)果:
注意:define定義的標識符只進行替換,并不會在替換過程中執(zhí)行運算,例如
#include <stdio.h> #define MAX 5+5 int main() { int i = 10; int x = i * MAX; printf("%d", x); return 0; }
這個程序的結(jié)果是多少呢?100嗎?答案其實是55,因為define只是簡單的替換,i*MAX其實本質(zhì)是i*5+5,即10*5+5=55.
3、#define定義的宏
語法:
#define SQUARE(x) x * x
當我們在程序中寫下:SQUARE(5)這句代碼,這預處理時,這句代碼就會被替換成5*5。例如:
#include <stdio.h> #define SQUARE(x) (x) * (x) int main() { int i = SQUARE(5); printf("%d", i); return 0; }
程序結(jié)果為:
注意:同樣的#define定義的宏也只是進行簡單的替換。
例如:
#include <stdio.h> #define SQUARE(x) x * x int main() { int a = 5; int i = SQUARE(a+1); printf("%d", i); return 0; }
這個程序的結(jié)果是什么呢?答案是11,SQUARE(a+1)等同于SQUARE(5+1),即5+1*5+1=11,而不是6*6=36。
宏常常被用于執(zhí)行簡單的運算,比如在兩個數(shù)中找出較大的一個。
#define MAX(a, b) ((a)>(b)?(a):(b))
那么為什么不用函數(shù)呢,因為宏有兩個優(yōu)勢:
1. 用于調(diào)用函數(shù)和從函數(shù)返回的代碼可能比實際執(zhí)行這個小型計算工作所需要的時間更多。所以宏比函數(shù)在程序 的規(guī)模和速度方面更勝一籌。
2. 更為重要的是函數(shù)的參數(shù)必須聲明為特定的類型。所以函數(shù)只能在類型合適的表達式上使用。反之這個宏怎可 以適用于整形、長整型、浮點型等可以用于>來比較的類型。宏是類型無關的。
但宏也有劣勢:
1. 每次使用宏的時候,一份宏定義的代碼將插入到程序中。除非宏比較短,否則可能大幅度增加程序的長度。
2. 宏是沒法調(diào)試的。
3. 宏由于類型無關,也就不夠嚴謹
4. 宏可能會帶來運算符優(yōu)先級的問題,導致程容易出現(xiàn)錯。(就是上面我提醒大家需要注意的地方)
4、#unef
這條指令用于移除一個#define定義標識符或宏定義。
例如:
#define MAX 100 int main() { int m = MAX; #undef MAX int n = MAX;//err return 0; }
這個程序會報錯,因為那個int n=MAX中的MAX的定義被移除了,而其他的不會(m仍然是正確的)。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關注腳本之家的更多內(nèi)容!
相關文章
opencv實現(xiàn)機器視覺檢測和計數(shù)的方法
在機器視覺中,有時需要對產(chǎn)品進行檢測和計數(shù)。其難點無非是對于產(chǎn)品的圖像分割。本文就來介紹一下機器視覺檢測和計數(shù)的實現(xiàn),感興趣的可以參考一下2021-05-05C語言中用于產(chǎn)生隨機數(shù)的函數(shù)使用方法總結(jié)
這篇文章主要介紹了C語言中用于產(chǎn)生隨機數(shù)的函數(shù)使用方法總結(jié),分別介紹了rand()函數(shù)和srand()函數(shù)以及封裝出的arc4random()函數(shù),需要的朋友可以參考下2016-05-05C/C++如何實現(xiàn)循環(huán)左移,循環(huán)右移
這篇文章主要介紹了C/C++如何實現(xiàn)循環(huán)左移,循環(huán)右移,具有很好的參考價值,希望對大家有所幫助。具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07將正小數(shù)轉(zhuǎn)化為2-9進制小數(shù)的實現(xiàn)方法
本篇文章對正小數(shù)轉(zhuǎn)化為2-9進制小數(shù)的實現(xiàn)方法進行了介紹,需要的朋友參考下2013-05-05C語言scandir函數(shù)獲取文件夾內(nèi)容的實現(xiàn)
scandir?函數(shù)用于列舉指定目錄下的文件列表,本文主要介紹了C語言scandir函數(shù)獲取文件夾內(nèi)容的實現(xiàn),具有一定的參考價值,感興趣的可以了解一下2024-03-03