c語言關於宏的使用十分頻繁。可是宏的使用有利也有弊,與此同時,它仍是一個特別容易搞錯的地方。正是基於此,它經常成爲一些面試會側重考察的地方。ios
所謂宏就是 #define 機制包括的一個規定,即容許把參數替換到文本中。它的聲明方式:#define name(參數列表) stuff 面試
其中參數列表是一個由逗號分隔的符號列表,對應參數做用於stuff中,至關於宏替換函數;若是沒有參數列表,那就是咱們日常用得比較多的宏替換變量了。安全
1. 分號問題函數
2. 符號優先級問題spa
3. 做用域問題調試
4.使用帶反作用的宏參數code
宏定義處用了分號blog
#include <iostream>
using namespace std; #define MAX( l, r) l > r? l: r;
int main() { int a =1 , b=2; if( a) int max = MAX( a,b);// <=> max = a > b? a:b;; 出錯!!
else { } return 0; }
符號優先級問題作用域
#include <iostream>
using namespace std; #define MAX( l, r) l > r? l: r
int main() { int a =1 , b=2; int max = MAX( a && 3, b);//a && 3 > b? a && 3: b 達不到預想結果
cout<<max; return 0; }
改造:io
#define MAX( l, r) ( (l)> (r)? (l) :(r) )
int main() { int a =1 , b=2; int max = MAX( a && 3, b);//(a && 3) > b? (a && 3) : b
cout<<max; return 0; }
做用域問題
#include <iostream> using namespace std; //=優先級很低,不用優先級問題 #define SWAP(l, r) {\ int tmp = l;\ l = r; \ r = tmp;} int main() { int a =1 , b=2; if(a) SWAP(a, b); //<=> {.... } ; 此處只容許出現一條語句,但這裏產生2條 else { } cout<<a <<" "<<b<<endl; return 0; }
解決:用do{... }while(0) 解決
//=優先級很低,不用優先級問題 #define SWAP(l, r) do{\ int tmp = l;\ l = r; \ r = tmp;}while(0) int main() { int a =1 , b=2; if(a) SWAP(a, b); //<=> do{.... }while( 0) ; else { } cout<<a <<" "<<b<<endl; return 0; }
帶反作用的宏參數
當宏參數在宏定義中出現次數超過一次時,若是這個參數具備反作用,那麼當使用這個宏時就出現危險,致使不可預料的結果。反作用就是在表達式求值時出現永久性的效果。好比x++,它能夠增長x的值。當下一次執行該表達式時,他將產生一個全新的結果。仍是之前面的的MAX函數爲例
#include <iostream>
using namespace std; #define MAX(l, r) ( (l)>(r)? (l): (r)) int main() { int a =1 , b=2; int max = MAX(a++, b++); //<=> (a++)>( b++)? ( a++):( b++); //結果: 3 2 4
cout<<max<<" "<<a<<" "<<b<<endl; return 0; }
結果讓較小的值a增長了一次,但確讓較大的值b增長了2次。這種帶反作用宏參數會修改變量的值,使用需格外注意。
優勢:
1. 快! 因爲是預處理時期直接宏替換,不用像函數那樣來回調用返回,增長額外開銷。
2. 因爲能夠替換變量,修改變量僅需在宏定義處修改,增長了程序的可維護性。
缺點:
1. 沒有類型安全的檢查。宏和類型是無關的,只要對參數操做合法,它可使用任何參數類型。
2. 極易出錯。 宏參數求值是要依賴於周圍表達式的上下文環境。沒有合理地加括號,得不到指望的結果; 同時參數每次用於宏定義時,它們都會從新求值,因爲這樣屢次求值,因此讓具備反作用的參數可能產生不可預料的結果。
3. 不可調試。因爲預處理階段,直接進行了宏替換,對替換掉的代碼沒法進行調試檢查。
4. 替換插入代碼,致使程序代碼長度大大加長。