C預編譯指令 -- #define
---------------------------------------------
-- 2018-01-06 建立人:Ruo_Xiao
-- 開發環境:VS2010
-- 郵箱:[email protected]
--------------------------------------
-- 2018-01-07 修改人:Ruo_Xiao
-- 新增#undef指令
---------------------------------------------
一、概括
1. 將一些文字替換成另外一些文字。
2. 以“#”開始,第一個換行符為止。可以出現在原始檔任何位置。
3. 有效範圍:從指令出現的地方到該檔案末尾或者該符號對應的#undef。
4. ANSI之後,允許預編譯指令的“#”前面新增空格和製表符,“#”和指令的其餘部分之間亦可有空格。但是,之前是不允許的(K&R C)。
5. 常用的預編譯指令:
#define、#undef、#include、#ifdef、#else、#endif、#ifndef、#if、#elif、#line、#error和#pragma 。
二、符號常量:#define
#define PI 3.1415926 #define Add(x,y) ((x)+(y)) //預編譯指令 巨集 替換體(替換列表) //X和Y被成為巨集引數。 //注意:上述例子中每一個括號都是不可缺少的。
1、作用:一旦前處理器在程式中找到該巨集,就會用替換體替換該巨集。
2、巨集變成最終替換文字的過程被稱為巨集展開。
3、巨集可以表示任何字串(數值、函式、字串)和其他巨集。
4、注意:巨集如果在雙引號裡面,預處理是不會進行文字替換的。
5、不帶引數的巨集
(1)如上圖中定義的“PI”。
(2)有的編譯器將巨集的替換體看作是記號型字串,而不是傳統意義上的字元型字串。C前處理器記號是巨集定義的替換體中單獨的“詞”,用空格把這些詞分開。
例如:
#define TWO 1*2
上述的巨集的替換體的記號為“1*2”,如果改成下例:
#define TWO 1 * 2
則記號就有三個,分別是“1”、“*”和“2”。
小結:巨集的替換體解釋為字元型字串,則將空格作為替換體的一部分。解釋為記號型字串,則把空格作為替換體中各記號的分隔符。
(3)重定義常量
同一檔案中,同一符號被定義了兩次以上,這個過程被稱為重定義常量。例如:
#define PI 3.1415
#define PI 3.1415926
這種情況下,有的編譯器報錯,有的編譯器警告,有的編譯器沒有任何提示資訊(VS2010),以最後一個符號定義為準。
例如:
#define x 9
#define x 10
int iSum[x];
這裡iSum中元素有10個。
6、帶引數的巨集
(1)巨集中使用引數的外形和函式很像的被稱為類函式巨集。
(2)巨集函式和函式呼叫完全不同,前者是在預編譯期,將引數記號傳給了程式,後者是在程式執行期將引數的值傳給了函式,即不同的過程發生在了不同的時期。
(2)應用:
Z = Add(3,7);
7、用巨集引數建立字串:#運算子
(1)一般的巨集在字串中都會被視為普通的文字,但是允許在巨集替換中的字串中包含巨集引數。“#x”就可轉換為字串“x”的形參名,這個過程被稱為字串化(注意使用“”)。
(2)例如:
#include "stdafx.h"
#include <stdio.h>
#define POST(x) printf("I am "#x",%d\n",((x)*(x)))
int _tmain(int argc, _TCHAR* argv[])
{
POST(10);
POST(2 + 3);
getchar();
return 0;
}
結果:
8、前處理器的粘合劑,“##”指令
(1)將兩個記號組合成一個記號
(2)例如:
#include "stdafx.h"
#include <stdio.h>
#define XNAME(n) iX##n
#define Print_Xn(n) printf("iX"#n" = %d\n",iX##n)
int _tmain(int argc, _TCHAR* argv[])
{
int XNAME(1) = 2; //相當於:int iX1 = 2
int XNAME(2) = 5; //相當於:int iX2 = 5
Print_Xn(1);
Print_Xn(2);
getchar();
return 0;
}
結果:
9、變參巨集
(1)指令如下:
"..." 和 "__VA_ARGS__"
這兩個指令組合可以讓使用者定義可變引數的類函式巨集。
(2)例如:
#include "stdafx.h"
#include <stdio.h>
#define Print_X(x,...) printf("x = "#x","__VA_ARGS__)
int _tmain(int argc, _TCHAR* argv[])
{
int x = 11;
int y = x*x;
Print_X(x,"y = %d\n",y);
getchar();
return 0;
}
結果:
10、巨集函式和普通函式的對比
(1)巨集定義只能寫在一行,雖然編譯器沒有硬性規定,但是請遵守這條約定。
(2)空間:使用巨集函式20個地方,就會有20個副本,但是函式只有一個。
(3)時間:巨集函式沒有函式跳轉,節省時間。如果巢狀呼叫,效果很明顯。
(4)巨集不用考慮形參的資料型別,因為在巨集眼裡,一切都是字串或者記號。
三、#undef
1. 取消之前的#define定義。
2. 即使之前沒有被定義,直接使用此指令也是沒有問題的。所以在使用某個符號時,若不確定之前是否已使用,可以在前面加上#undef。
四、拓展
字元常量和符號常量的區別
(1)字元常量:直接在程式碼中書寫的數值,例如:5.78、3.1415、7。
(2)符號常量:用一個識別符號代替一個常量。先定義後使用,例如:#define PI 3.1415926
(SAW:Game Over!)