之 編譯預處理與宏定義
宏是編譯預處理的重要定義,宏定義就像基本數據類型定義同樣,能夠看做是一種類型,與基本類型不一樣的是,宏與函數有着密切的類似之處,可是宏是編譯時發生做用。
1. 通常格式:
#define 標識符 字符串 標識符即爲這個字符串的宏名
2. 宏調用:程序中用宏名代替字符串。
宏展開:預編譯時將字符串代替宏名的過程。
好比:#define PI 3.14
這裏的PI就是宏名,他表明的是字符串3.14,預編譯時將源程序中的全部宏名PI出現的位置都用字符串3.14來替換。好比: 程序中出現PI*5,它的結果其實是 3.14*5
(1)宏名用大寫,用來區分普通變量
(2)宏定義不能以分號結束,不然分號將做爲字符串的一部分參加宏展開。好比:
#define PI 3.1415; //結尾加了分號
a=PI*r*r;
|
在編譯預處理時,將宏展開: a=3.1415;*r*r 分號將做爲字符串參加運算,很明顯是錯誤的
(3)宏定義只是用來替換字符串的。 無論字符串是什麼數據類型,總之就是一句話,宏名替換字符串,宏名替換的必定是字符串,即便上述中的3.1415寫成了3.1W15。替換後的結果依然是a=3.1W15*r*r。
(4)#define命令定義的宏名範圍是從定義命令開始直到源程序文件結束,並且#define定義在文件開頭與函數之間。 若是要想提早結束宏定義的做用域,能夠經過#undef終止宏名的做用域
(5)宏定義中能夠出現已經定義的宏名,能夠層層置換。
若宏名中 出現一個被雙引號括起來的字符串中時,將不會產生宏替換。
好比:
#include <stdio.h> /*宏定義在文件頭和函數之間*/ #define R 3.0 #define PI 3.1415926 #define L 2*PI*R //出現了前面已經定義的PI和R #define S PI*R*R //出現了前面已經定義的PI和 main() { /* 當L和S在「」以內時將不會與宏定義產生聯繫,即不會發生替換 當L和S不在「」以內時,L將被替換成 2*PI*R,S將被替換成 PI*R*R */ printf("L=%7.2f\nS=%7.2f\n",L,S); } |
最後須要注意的是: 宏定義是專用於預處理的一個名詞,它的做用就是替換,不分配空間
通常格式:
#define 宏名(參數表) 字符串
帶參數的宏定義並不單單是宏名代換字符串,還要進行參數的替換,相似於函數的調用
好比:
#define S(a,b) a*b
area=S(3,2);
|
S爲宏名,a和b爲形參,程序中調用S(3,2),把實參3和2分別替換形參a和b,因此宏展開是area=3*2;
好比:
#include <stdio.h> /*宏定義在文件頭和函數之間*/ #define S(a,b) a*b //須要注意的是S和()之間不能有空格 main() { int area; area=S(2,3);//傳遞給宏S(a,b),而後替換爲a*b printf("area=%d\n",area); } |
(1)上述程序中的參數傳遞應該很好理解,可是若是把程序改動一下,讓實參的值變成S(2+3,3+4), 你們確定會認爲是35,可是真的是35嗎? 咱們看一下:
#include <stdio.h> /*宏定義在文件頭和函數之間*/ #define S(a,b) a*b //須要注意的是S和()之間不能有空格 main() { int area; area=S(2+3,3+4); printf("area=%d\n",area); } |
居然是15,並非咱們想象中的35,怎麼回事呢? 實際上S(2+3,3+4)傳遞過去後,它的紅替換是 area=2+3*3+4,這下你們明白了吧。仍是一句話,宏定義只是用來替換的,完徹底全的原樣的替換。那要怎麼解決這個問題呢?很簡單,在宏定義的時候加上一個括號就能夠了,看程序:
#include <stdio.h> /*宏定義在文件頭和函數之間*/ #define S(a,b) (a)*(b) //須要注意的是S和()之間不能有空格 main() { int area; area=S(2+3,3+4);//傳遞給宏S(a,b),而後替換爲a*b printf("area=%d\n",area); } |
(2)宏定義的宏調用與函數調用的區別
在學習了帶參數的宏定義後,是否是以爲這個調用與函數的調用很類似,可是它們徹底是不通的兩個概念:
函數調用時,先求出實參表達式的值,再將該值傳遞個形參,而帶參數的宏調用只是進行替換,簡單的字符替換
函數調用是在程序運行時處理,分配給形參臨時內存單元,而宏展開則在編譯時進行的,展開的時並不給形參分配內存單元,不進行值傳遞,也沒有返回值