預處理是程序編譯前的一個預先處理的動做,編譯一共有4個步驟:C原文件 --> 預處理 --> 編譯 --> 彙編 -> 連接 --> 可執行文件。
預處理的工做主要是展開咱們C源碼中的#開頭的語句,去掉了全部的註釋,在嚴格的意義來講,這些語句它並不屬於C語言的語法範疇。
如下是預處理的一些指令:
1.頭文件 : #include
2.宏定義 : #define
3.取消宏 : #undef
4.條件編譯 : #if \ #ifdef \ #ifndef \ #else \ #elif \ #enif
5.顯示錯誤 : #error
6.修改當前文件的名字行號 :#line
7.向編譯器中發送特定的指令 : #progma
能夠在編譯程序的時候添加一個-E的選項,讓編譯器在預處理以後停下來不要繼續往下走,macro.i是源程序將#展開的內容。數組
gcc macro.c -o macro.i -E
宏(macro)實際上以一段字串,在源碼中只是用來直接替換目標位置,通常宏都使用全大寫字母(這只是一個習慣)。函數
#define PI 3.141592 #define BUF_SIZE 64 int main (int argc, char const *argv[]){ printf("PI:lf\t" , PI); int a = 100 + PI ; printf("a:%d\n", a); } 輸出:PI:3.141592 a:103
注意:
1.PI就是一個宏,在咱們的源代碼中若是出現宏的使用,則經過預處理以後會直接被替換,只是直接的字符替換而已,不會考慮語法或運算關係。code
無參宏意味着咱們在使用的時候不須要傳遞參數內存
#define BUF_SIZE 64 int main (int argc, char const *argv[]){ int arr[BUF_SIZE]; //定義了一個int型數組,大小爲64個 }
注意:
1.宏他的本指就值直接的替換,沒有任何的語法檢查;
2.使用宏的狀況下若是代碼有跟新迭代時,只須要修改宏的一處,整個代碼中全部用到宏的地方都會被修改;
3.宏的名字能夠提升代碼的可讀性。編譯器
帶參宏 在使用的時候須要攜帶參數來使用。源碼
#define MAX(a,b) a>b ? a : b int main (int argc, char const *argv[]){ printf("%d\t" , MAX(100,998) ); printf("%d\n" , 100>998 ? 100 : 998 ); } 輸出:998 998
注意:
1.使用帶參宏的時候也是直接替換。
2.只是存粹的文本替換,沒有任何的語法檢查/判斷,也沒有任何的運算
3.宏在預處理以後已經被替換,代碼實際運行時是不須要額外的時間開銷,只會浪費一點內存的空間。編譯
因爲宏只是存粹的文本替換,中間不涉及任何的計算與語法檢查,類型匹配,因此用起來會比用函數麻煩不少。gcc
#define MAX(a,b) a>b ? a : b int main (int argc, char const *argv[]){ int x = 100; int y = 200; printf("MAX:%d\n" , MAX(x,y == 200 ? 888:999 ) );
從以上的代碼中, 無論表達式 y == 200 ? 888:999 的值都是大於 x ,可是卻出來最大值爲x 、
觀察一下替換後的結果:語法
printf("MAX:%d\n" , x>y == 200 ? 888:999 ? x : y == 200 ? 888:999 ); //注意從右向左運算,?的優先級大於:
因此應該修改長以下:gc
#define MAX(a,b) (a)>(b) ? (a) : (b) printf("MAX:%d\n" , (x)>(y == 200 ? 888:999) ? (x) : (y == 200 ? 888:999) );
使用括號對宏當中的每一項括起來,提升優先級,這樣替換以後邏輯不會出現問題。