預處理器指令#define和其他預處理器指令一樣,都是從#開始運行,到第一個換行符結束爲止,也就是說預處理器指令的長度僅限於一個邏輯行(C語言中以 ; 作爲語句的結束,不以行爲單位結束,當一行的內容太長不方便卸載一行時可使用反斜槓"\"作爲繼續符,分爲多行書寫) ,在預處理開始前編譯器會把多行物理行處理爲一行邏輯行。
#define LED_RGBOFF LED_R_OFF;\ /*反斜槓把該定義延續到下一行*/
LED_G_OFF;\
LED_B_OFF
等效於
#define LED_RGBOFF LED_R_OFF;LED_G_OFF; LED_B_OFF
每行#define(邏輯行)都是由三部分構成
#define PBGOFF LED_R_OFF
第一部分 第二部分 第三部分
第一部分是預處理器指令本身#define
第二部分是用戶自己定義的名字,也成爲宏 ,有些宏代表值(如上例所示),這些宏被稱爲類對象宏,c語言還有類函數宏會在接下來介紹,宏的名稱與變量的命名規則相同。只能使用字符數字和下劃線,且首字符不能使數字。
第三部分稱爲替換列表或替換體 ,預處理找到宏後會用替換體代替宏。
例如:
#include <stdio.h>
#define student_amount 10
#define square_stu student_amount*student_amount
#define pa printf("A is %d.\n",a)
#define zxc "A is %d.\n"
int main()
{ /* 等效於 */
int a = student_amount; /* int a = 10 */
pa; /* printf("A is %d.\n",a) */
a = square_stu; /* a = 10*10 */
printf(zxc,a); /* printf("A is %d.\n",a) */
return 0;
}
運行上述程序後輸出如下:
A is 10.
A is 100.
在進行預編譯時,預處理器不做計算,不對表達式求值,只進行替換。
在前面提到過在一行的結尾加上反斜槓則可以使該行擴展至下一行如下所示
#define kabuda "yuzhouwudi\
dashuaige" /*反斜槓把該定義延續到下一行*/
注意,第二行要與第一行對齊,如果這樣做
#define kabuda "yuzhouwudi\
dashuaige" /*反斜槓把該定義延續到下一行*/
printf(kabuda);
那麼輸出的內容是
kabuda "yuzhouwudi dashuaige"
從第二行開始到da之間的空格也算是字符串的一部分。
一般而言,預處理器發現程序的宏後,會用宏對應的替換體進行替換,如果替換的字符串中還包含宏,則繼續替換這些宏。唯一例外的是雙引號中的宏。
如
printf("kabuda");
那麼輸出的結果是
kabuda
另外在#define中使用參數可以創建外形和作用與函數類似的類函數宏 ,帶有參數的宏看上去很像函數,因爲這樣的宏也使用圓括號。類函數宏定義的圓括號中可以有一個或多個參數,隨後這些參數出現在替換體中。
#define square_parameter(x) x*x
看上去和函數調用沒有什麼不同,其實還是有本質的區別,如下例所示,帶有一些陷阱。
#include <stdio.h>
#define square_paramemter(a) a*a
int main()
{
int x = 10;
int z;
z = x;
printf("z = %d\n", z);
z = square_paramemter(x);
printf("z = %d\n", z);
z = square_paramemter(x+2);
printf("z = %d\n", z);
return 0;
}
輸出結果是
z = 10
z = 100
z = 22
第三個z爲什麼不是144,而是22,是因爲我們前面提到的。預處理器不做計算,不求值,只替換字符序列,所以爲10+2*10+2結果爲22。
所以爲了避免上例的錯誤,我們可以在宏定義的時候多加幾個括號
#define square_paramemter(a) ((a)*(a))