談起C++中的宏,我們第一個想到的應該就是“#define”,它的基本語法長得像這樣:
1 #define macroname(para1, para2, para3, ... ,paran) macro-body
宏的聲明和普通的函數聲明很像,但是兩者之間有本質的區別:C++函數在運行時(runtime)才執行代碼段;而宏則是在預編譯時期(preprocessor)執行代碼段。下面簡單介紹一下幾個宏的應用。
一、考慮下面的代碼段:
1 #define PLUS_ONE(x) ((x) + 1) 2 int x=PLUS_ONE(12);
>>>x=((12) + 1)
>>>x=13
這是最簡單的應用,用macro-body替換macroname;和C函數不一樣的是,宏是沒有返回值的,本身表達式的值將作為返回值傳回。
二、考慮下面的代碼段:
1 #define x 1+2 2 int t=x*3; 3 std::cout<<t<<'\n';
那么輸出t的值會是什么呢?答案也許不是你期望中的9,而是7。原因很簡單,#define的替換實質上是表達式的替換,將上述代碼里的宏展開后將變成這樣:
int t = 1 + 2 * 3; //t = 7
這種結果顯然不是我們願意看到的,而且這種錯誤是很難察覺的,完全沒有語法錯誤和語義錯誤;不過要解決這個問題也很容易,將表達式括起來就行了:
1 #define x (1+2)
>>>int t = (1+2)*3=9
不過這種使用宏的方法是不推薦的,因為容易引起一些不必要且難以察覺的錯誤。在C++里,我們完全可以這樣聲明x,也能達到同樣的目的:
1 const int x=3; //聲明常數推薦用const關鍵字
三、Preprocessor預先定義好的值;
__FILE__ :編譯的文件的絕對路徑;
__LINE__ :當前行號;
__TIME__ :當前時間;
__DATE__ :當前日期。
四、C語言中macro的設計初衷之一是關於內聯函數。如果我們定義一個求較大值的MAX函數:
1 #define MAX(a,b) ((a)>(b)?(a):(b))
>>>int myInt=MAX(x,y)
>>>int myInt=((x)>(y)?(x):(y)) //上一行調用的宏將直接這樣插入到代碼段里
如果我們將MAX寫成一個一般的函數,那么我們調用MAX將有以下兩個過程:①調用名稱為MAX的函數 ②將比較得到的值返回。顯然在這兩種方案中,macro的方案更較高效,因為它省略的函數調用的開銷,直接能得到結果(相當於inline函數的用法,這里不展開講inline了)。
五、字符串操作函數
看如下macro定義:
1 #define MAX(a,b) ((a)>(b)?(a):(b))
這里的參數a和b實際上都是以string的方式傳遞的,例如MAX(10,12)返回的是字符串"12",而不是整型的12。預處理器提供兩種方式處理string類型的參數傳遞。
1、stringizing operator '#':返回一個C風格的字符串;
1 #define TEST(n) std::cout << #n << " is " << (n) << std::endl
>>>int x= 6;
>>>TEST(x*2); //std::cout << "x*2" << " is " << (x*2) << std::endl
最終得到的結果是:x*2 is 12
那么這種看似tricky的語法有什么用呢?其實,當上述C++代碼被翻譯成機器碼時,所有和變量x相關的概念或者語句都會被“消滅”,因為變量只會存在於C++代碼層;而通過stringizing operator,讓我們以字符串的形式保存一部分C++源代碼變得可能,這可以應用於寫一些“自我診斷(糾錯)”的函數中,有機會再深入介紹吧!
2、string concatenation operator '##':顧名思義,字符串連接算子:
1 #define TEST2(type) type ones_##type
>>>TEST2(int);
>>>int ones_type; //這個宏的功能其實就是聲明一個任意類型的,如int的變量,名字叫做ones_type
這個沒感覺有什么特別的用途,trick。