【黑马程序员】————预处理指令1-宏定义
------Java培訓(xùn)、Android培訓(xùn)、iOS培訓(xùn)、.Net培訓(xùn)、期待與您交流! -------
?
預(yù)處理指令簡(jiǎn)介
1.C語(yǔ)言在對(duì)源程序進(jìn)行編譯之前,會(huì)先對(duì)一些特殊的預(yù)處理指令作解釋(比如之前使用的#include文件包含指令),產(chǎn)生一個(gè)新的源程序(這個(gè)過程稱為編譯預(yù)處理),之后再進(jìn)行通常的編譯
2.為了區(qū)分預(yù)處理指令和一般的C語(yǔ)句,所有預(yù)處理指令都以符號(hào)"#"開頭,并且結(jié)尾不用分號(hào) 3.預(yù)處理指令可以出現(xiàn)在程序的任何位置,它的作用范圍是從它出現(xiàn)的位置到文件尾。習(xí)慣上我們盡可能將預(yù)處理指令寫在源程序開頭,這種情況下,它的作用范圍就是整個(gè)源程序文件 4.C語(yǔ)言提供的預(yù)處理指令主要有:宏定義、文件編譯、條件包含 宏定義可以分為2種:不帶參數(shù)的宏定義 和 帶參數(shù)的宏定義。一、不帶參數(shù)的宏定義
1.一般形式
#define?宏名?字符串
?比如#define ABC 10
右邊的字符串也可以省略,比如#define ABC
?
2.作用
它的作用是在編譯預(yù)處理時(shí),將源程序中所有"宏名"替換成右邊的"字符串",常用來定義常量。
接下來寫個(gè)程序根據(jù)圓的半徑計(jì)算周長(zhǎng)
1 #include <stdio.h> 2 3 // 源程序中所有的宏名PI在編譯預(yù)處理的時(shí)候都會(huì)被3.14所代替 4 #define PI 3.14 5 6 // 根據(jù)圓的半徑計(jì)radius算周長(zhǎng) 7 float girth(float radius) { 8 return 2 * PI *radius; 9 } 10 11 int main () 12 { 13 float g = girth(2); 14 15 printf("周長(zhǎng)為:%f", g); 16 return 0; 17 }在第4行定義了一個(gè)叫PI的宏,在編譯預(yù)處理之后,第8行中的2 * PI *radius就會(huì)變成2 * 3.14 * radius。
輸出結(jié)果:
3.使用習(xí)慣與注意
1> 宏名一般用大寫字母,以便與變量名區(qū)別開來,但用小寫也沒有語(yǔ)法錯(cuò)誤
2> 對(duì)程序中用雙引號(hào)擴(kuò)起來的字符串內(nèi)的字符,不進(jìn)行宏的替換操作。比如:
1 #define R 10 2 int main () 3 { 4 char *s = "Radio"; 5 return 0; 6 }在第1行定義了一個(gè)叫R的宏,但是第4行中"Radio"里面的'R'并不會(huì)被替換成10
3> 在編譯預(yù)處理用字符串替換宏名時(shí),不作語(yǔ)法檢查,只是簡(jiǎn)單的字符串替換。只有在編譯的時(shí)候才對(duì)已經(jīng)展開宏名的源程序進(jìn)行語(yǔ)法檢查
1 #define I 100 2 int main () 3 { 4 int i[3] = I; 5 return 0; 6 }在做編譯預(yù)處理的時(shí)候,不管語(yǔ)法對(duì)不對(duì),第4行的I都會(huì)被替換為100。不過在編譯的時(shí)候就會(huì)報(bào)第4行的錯(cuò)。
4> 宏名的有效范圍是從定義位置到文件結(jié)束。如果需要終止宏定義的作用域,可以用#undef命令
1 #define PI 3.14 2 /* 3 . 4 . 5 . 6 . 7 */ 8 #undef PIPI這個(gè)宏在第1行到第8行之間是有效的,第8行后就無效了
5> 定義一個(gè)宏時(shí)可以引用已經(jīng)定義的宏名
1 #define R 3.0 2 #define PI 3.14 3 #define L 2*PI*R 4 #define S PI*R*R二、帶參數(shù)的宏定義
1.一般形式
#define?宏名(參數(shù)列表) 字符串
2.作用
在編譯預(yù)處理時(shí),將源程序中所有宏名替換成字符串,并且將 字符串中的參數(shù) 用 宏名右邊參數(shù)列表 中的參數(shù)替換
1 #include <stdio.h> 2 3 #define average(a, b) (a+b)/2 4 5 int main () 6 { 7 int a = average(10, 4); 8 9 printf("平均值:%d", a); 10 return 0; 11 }?第3行中定義了一個(gè)帶有2個(gè)參數(shù)的宏average,第7行其實(shí)會(huì)被替換成:int?a = (10 +?4)/2;,輸出結(jié)果為:。
3.使用注意
1> 宏名和參數(shù)列表之間不能有空格,否則空格后面的所有字符串都作為替換的字符串
1 #define average (a, b) (a+b)/2 2 3 int main () 4 { 5 int a = average(10, 4); 6 return 0; 7 }注意第1行的宏定義,宏名average跟(a, b)之間是有空格的,于是,第5行就變成了這樣:
1 int a = (a, b) (a+b)/2(10, 4);這個(gè)肯定是編譯不通過的
2>?帶參數(shù)的宏在展開時(shí),只作簡(jiǎn)單的字符和參數(shù)的替換,不進(jìn)行任何計(jì)算操作。所以在定義宏時(shí),一般用一個(gè)小括號(hào)括住字符串的參數(shù)。
下面定義一個(gè)宏D(a),作用是返回a的2倍數(shù)值:
- 如果定義宏的時(shí)候不用小括號(hào)括住參數(shù)
- 1 #include <stdio.h>
2
3 #define D(a) 2*a
4
5 int main ()
6 {
7 int b = D(3+4);
8
9 printf("%d", b);
10 return 0;
11 }
第7行將被替換成int?b = 2*3+4;,輸出結(jié)果:
- 如果定義宏的時(shí)候用小括號(hào)括住參數(shù),把上面的第3行改成: #define D(a) 2*(a)
注意右邊的a是有括號(hào)的,第7行將被替換成int?b = 2*(3+4);,輸出結(jié)果:
3> 計(jì)算結(jié)果最好也用括號(hào)括起來
下面定義一個(gè)宏P(guān)(a),作用是返回a的平方:
*如果不用小括號(hào)括住計(jì)算結(jié)果
1 #include <stdio.h> 2 3 #define Pow(a) (a) * (a) 4 5 int main(int argc, const char * argv[]) { 6 int b = Pow(10) / Pow(2); 7 8 printf("%d", b); 9 return 0; 10 }注意第3行,沒有用小括號(hào)擴(kuò)住計(jì)算結(jié)果,只是括住了參數(shù)而已。第6行代碼被替換為:
int b = (10) * (10) / (2) * (2);簡(jiǎn)化之后:int?b = 10 * (10 / 2) * 2;,最后變量b為:
*如果用小括號(hào)括住計(jì)算結(jié)果
將上面的第3行代碼改為:
#define Pow(a) ( (a) * (a) )那么第6行被替換為:
int b = ( (10) * (10) ) / ( (2) * (2) );簡(jiǎn)化之后:int?b = (10 * 10) / (2 * 2);,最后輸出結(jié)果:。這個(gè)才是我們想要的結(jié)果。
5.與函數(shù)的區(qū)別
從整個(gè)使用過程可以發(fā)現(xiàn),帶參數(shù)的宏定義,在源程序中出現(xiàn)的形式與函數(shù)很像。但是兩者是有本質(zhì)區(qū)別的:
1>?宏定義不涉及存儲(chǔ)空間的分配、參數(shù)類型匹配、參數(shù)傳遞、返回值問題
2>?函數(shù)調(diào)用在程序運(yùn)行時(shí)執(zhí)行,而宏替換只在編譯預(yù)處理階段進(jìn)行。所以帶參數(shù)的宏比函數(shù)具有更高的執(zhí)行效率
?
轉(zhuǎn)載于:https://www.cnblogs.com/Jr-711/p/3896697.html
總結(jié)
以上是生活随笔為你收集整理的【黑马程序员】————预处理指令1-宏定义的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Vessels
- 下一篇: webview改变网页宽度