C/C++ 的巨集中#和##的作用和展開
阿新 • • 發佈:2018-12-20
C/C++ 的巨集中:
(1) # 的功能是將其後面的巨集引數進行字串化操作,簡單說就是在對它所引用的巨集變數通過替換後在其左右各加上一個雙引號。
也就是說:
#define __TO_STRING_IMPL(x) #x
中的#X, 則巨集變數X所引用的是巨集引數中的X,因為,#X會直接對引數X進行字串化,因此該引數輸出的是字串“X”。
使用: __TO_STRING_IMPL(15), 輸出:“15”
為了能夠進一步增加巨集的引數輸入,因此需要在外部再包括一個巨集轉化,這樣就可以把"轉化巨集"中的具體引數傳入到引數化巨集中,這樣就可以變為相應“具體引數”的字串。
如下圖所示:
#define __TO_STRING(x) __TO_STRING_IMPL(x)
(2) ##連線符號由兩個井號組成,其功能是在帶引數的巨集定義中將兩個子串聯接起來,從而形成一個新的子串。但它不可以是第一個或者最後一個子串。
作用:只是用所引用的巨集變數替換後,將兩個字串串接起來,形成新的字串。
如下:
#define A(x) T_##x
使用:A(1),則輸出:T_1
(3)#@, 表示將引數作為字元形式替換
如下:
#define B(x) #@x
使用: B(1),輸出:’1‘
凡是巨集定義裡有用#或##的地方巨集引數是不會再展開,例如_STRI(INT_MAX)中的INT_MAX就不會被展開為2147483647。
如果想要使其中的巨集引數展開,則需要多加一層中間轉換巨集: #define STRI(s) _STRI(s)
加這層巨集的用意是把所有巨集的引數在這層裡全部展開,那麼在轉換巨集裡的巨集就能得到對應的巨集引數。
#ifndef __TO_STRING #define __TO_STRING_IMPL(x) #x #define __TO_STRING(x) __TO_STRING_IMPL(x) #endif
例子如下:
#include "stdafx.h" #include <iostream> #include<stdio.h> using namespace std; #define f(a,b) a##b #define g(a) #a #define h(a) g(a) #define A(x) T_##x #define B(x) #@x #define C(x) #x //如果EXP為真, 則輸出巨集引數“EXP”所指的字串, //注意:引數直接用真實引數替換。 #define WARN_IF(EXP) if(EXP) cerr << #EXP << endl; //將紅引數“n”,真實引數替換後 #define paster( n ) cout << "token" << #n << " = " << n << endl; //兩個巨集引數,連線“巨集引數”替換後形成字串 #define _CONS(a, b) int(a##+##b) #define _STRI(s) #s #define STRI(s) _STRI(s) void test_sharp_symbol() { printf("%s\n", h(f(1, 2))); //輸出:12 因為:h是轉化的巨集,其引數還是一個巨集變數,則需要轉化。 printf("%s\n", g(f(1, 2))); //輸出:f(1,2) 因為:g直接把指代的引數以“字串”輸出 printf("%s\n", h(A(1))); // A(1)------〉T_1 printf("%d\n", B(1)); // B(1)------〉'1' printf("%s\n", C(1)); // C(1)------〉"1" int div = 0; WARN_IF(div == 0); //輸出: div == 0 paster(9); //輸出: token9 = 9 cout << _CONS(1 + 2, 2) << endl; //輸出: 5 , 即: int(3+2), 輸出5 cout << _STRI(INT_MAX) << endl; //輸出: INT_MAX ,因為INT_MAX,本質上是一個巨集,但是作為巨集引數,則直接以字串輸出。 cout << STRI(INT_MAX) << endl; // prints : 2147483647 因為: INT_MAX ,再 STRI中已經替換為真實“資料”,從而可以以字串輸出 } int _tmain(int argc, _TCHAR* argv[]) { test_sharp_symbol(); system("pause"); return 0; }
輸出如下: