c語言宏的用法
C語言程序中廣泛的使用宏定義,採用關鍵字define進行定義,宏只是一種簡單的字符串替換,根據是否帶參數分爲無參和帶參。宏的簡單應用很容易掌握,下面小編就跟大家分享下c語言宏的用法。 c語言宏的用法如下:
1.宏的基本構成 (1)宏中包含特殊符號:#、##. (2)宏定義用do{ }while(0) 2、特殊符號#、## (1)# Whenyouputa#beforeanargumentinapreprocessor macro,thepreprocessorturnsthatargumentintoacharacterarray. 在一個宏中的參數前面使用一個#,預處理器會把這個參數轉換爲一個字符數組 簡化理解:#是“字符串化”的意思,出現在宏定義中的#是把跟在後面的參數轉換成一個字符串 #define ERROR_LOG(module) fprintf(stderr,"error: "#module"n") ERROR_LOG("add"); 轉換爲 fprintf(stderr,"error: "add"n"); ERROR_LOG(devied =0); 轉換爲 fprintf(stderr,"error: devied=0n"); (2)## “##”是一種分隔連接方式,它的作用是先分隔,然後進行強制連接。 在普通的宏定義中,預處理器一般把空格解釋成分段標誌,對於每一段和前面比較,相同的就被替換。但是這樣做的結果是,被替換段之間存在一些空格。如果我們不希望出現這些空格,就可以通過添加一些##來替代空格。 1 #define TYPE1(type,name) type name_##type##_type 2 #define TYPE2(type,name) type name##_##type##_type TYPE1(int, c);轉換爲:int name_int_type ; (因爲##號將後面分爲 name_ 、type 、 _type三組,替換後強制連接) TYPE2(int, d);轉換爲: int d_int_type ;(因爲##號將後面分爲 name、_、type 、_type四組,替換後強制連接) 3、宏定義中do{ }while(0) 第一眼看到這樣的宏時,覺得非常奇怪,爲什麼要用do……while(0)把宏定義的多條語句括起來?非常想知道這樣定義宏的好處是什麼,於是google、百度一下了。 採用這種方式是爲了防範在使用宏過程中出現錯誤,主要有如下幾點: (1)空的宏定義避免warning: #define foo() do{}while(0) (2)存在一個獨立的block,可以用來進行變量定義,進行比較複雜的實現。 (3)如果出現在判斷語句過後的宏,這樣可以保證作爲一個整體來是實現: #define foo(x) action1(); action2(); 在以下情況下: if(NULL == pPointer) foo(); 就會出現action1和action2不會同時被執行的情況,而這顯然不是程序設計的目的。 (4)以上的第3種情況用單獨的{}也可以實現,但是爲什麼一定要一個do{}while(0)呢,看以下代碼: #define switch(x,y) {int tmp; tmp="x";x=y;y=tmp;} if(x>y) switch(x,y); else //error, parse error before else otheraction(); 在把宏引入代碼中,會多出一個分號,從而會報錯。這對這一點,可以將if和else語句用{}括起來,可以避免分號錯誤。 使用do{….}while(0)把它包裹起來,成爲一個獨立的語法單元,從而不會與上下文發生混淆。同時因爲絕大多數的編譯器都能夠識別do{…}while(0)這種無用的循環並進行優化,所以使用這種方法也不會導致程序的性能降低 4、測試程序 簡單寫個測試程序,加強練習,熟悉一下宏的高級用法。 1 #include <stdio.h> 2 3 #define PRINT1(a,b) 4 { 5 printf("print an"); 6 printf("print bn"); 7 } 8 9 #define PRINT2(a, b) 10 do{ 11 printf("print an"); 12 printf("print bn"); 13 }while(0) 14 15 #define PRINT(a) 16 do{ 17 printf("%s: %dn",#a,a); 18 printf("%d: %dn",a,a); 19 }while(0) 20 21 #define TYPE1(type,name) type name_##type##_type 22 #define TYPE2(type,name) type name##_##type##_type 23 24 #define ERROR_LOG(module) fprintf(stderr,"error: "#module"n") 25 26 main() 27 { 28 int a = 20; 29 int b = 19; 30 TYPE1(int, c); 31 ERROR_LOG("add"); 32 name_int_type = a; 33 TYPE2(int, d); 34 d_int_type = a; 35 36 PRINT(a); 37 if (a > b) 38 { 39 PRINT1(a, b); 40 } 41 else 42 { 43 PRINT2(a, b); 44 } 45 return 0; 46 }
1.宏的基本構成 (1)宏中包含特殊符號:#、##. (2)宏定義用do{ }while(0) 2、特殊符號#、## (1)# Whenyouputa#beforeanargumentinapreprocessor macro,thepreprocessorturnsthatargumentintoacharacterarray. 在一個宏中的參數前面使用一個#,預處理器會把這個參數轉換爲一個字符數組 簡化理解:#是“字符串化”的意思,出現在宏定義中的#是把跟在後面的參數轉換成一個字符串 #define ERROR_LOG(module) fprintf(stderr,"error: "#module"n") ERROR_LOG("add"); 轉換爲 fprintf(stderr,"error: "add"n"); ERROR_LOG(devied =0); 轉換爲 fprintf(stderr,"error: devied=0n"); (2)## “##”是一種分隔連接方式,它的作用是先分隔,然後進行強制連接。 在普通的宏定義中,預處理器一般把空格解釋成分段標誌,對於每一段和前面比較,相同的就被替換。但是這樣做的結果是,被替換段之間存在一些空格。如果我們不希望出現這些空格,就可以通過添加一些##來替代空格。 1 #define TYPE1(type,name) type name_##type##_type 2 #define TYPE2(type,name) type name##_##type##_type TYPE1(int, c);轉換爲:int name_int_type ; (因爲##號將後面分爲 name_ 、type 、 _type三組,替換後強制連接) TYPE2(int, d);轉換爲: int d_int_type ;(因爲##號將後面分爲 name、_、type 、_type四組,替換後強制連接) 3、宏定義中do{ }while(0) 第一眼看到這樣的宏時,覺得非常奇怪,爲什麼要用do……while(0)把宏定義的多條語句括起來?非常想知道這樣定義宏的好處是什麼,於是google、百度一下了。 採用這種方式是爲了防範在使用宏過程中出現錯誤,主要有如下幾點: (1)空的宏定義避免warning: #define foo() do{}while(0) (2)存在一個獨立的block,可以用來進行變量定義,進行比較複雜的實現。 (3)如果出現在判斷語句過後的宏,這樣可以保證作爲一個整體來是實現: #define foo(x) action1(); action2(); 在以下情況下: if(NULL == pPointer) foo(); 就會出現action1和action2不會同時被執行的情況,而這顯然不是程序設計的目的。 (4)以上的第3種情況用單獨的{}也可以實現,但是爲什麼一定要一個do{}while(0)呢,看以下代碼: #define switch(x,y) {int tmp; tmp="x";x=y;y=tmp;} if(x>y) switch(x,y); else //error, parse error before else otheraction(); 在把宏引入代碼中,會多出一個分號,從而會報錯。這對這一點,可以將if和else語句用{}括起來,可以避免分號錯誤。 使用do{….}while(0)把它包裹起來,成爲一個獨立的語法單元,從而不會與上下文發生混淆。同時因爲絕大多數的編譯器都能夠識別do{…}while(0)這種無用的循環並進行優化,所以使用這種方法也不會導致程序的性能降低 4、測試程序 簡單寫個測試程序,加強練習,熟悉一下宏的高級用法。 1 #include <stdio.h> 2 3 #define PRINT1(a,b) 4 { 5 printf("print an"); 6 printf("print bn"); 7 } 8 9 #define PRINT2(a, b) 10 do{ 11 printf("print an"); 12 printf("print bn"); 13 }while(0) 14 15 #define PRINT(a) 16 do{ 17 printf("%s: %dn",#a,a); 18 printf("%d: %dn",a,a); 19 }while(0) 20 21 #define TYPE1(type,name) type name_##type##_type 22 #define TYPE2(type,name) type name##_##type##_type 23 24 #define ERROR_LOG(module) fprintf(stderr,"error: "#module"n") 25 26 main() 27 { 28 int a = 20; 29 int b = 19; 30 TYPE1(int, c); 31 ERROR_LOG("add"); 32 name_int_type = a; 33 TYPE2(int, d); 34 d_int_type = a; 35 36 PRINT(a); 37 if (a > b) 38 { 39 PRINT1(a, b); 40 } 41 else 42 { 43 PRINT2(a, b); 44 } 45 return 0; 46 }