---------------------------------------------------------------
3.3.8 將記號轉換為字串 [C語言參考手冊,p38(r54)]
---------------------------------------------------------------
標準C語言中有一種機制可以將宏參數(擴充之後)轉換為字串型常量。在此之前,編程人員要利用許多C語言前置處理器中的漏洞以不同方式達到相同結果。
在標準C語言中,宏定義中出現的#記號被當作一元“字串化”運算子,後面為宏正式參數名。宏擴充期間,#和正式參數名換成相應的包含在字串引號當中的實際參數。產生字串時,記號參數表中的每個空白序列換成一個空格符,任何嵌人引號和反斜線前面加上一個反斜線以保留其在字串中的含義。參數開頭和末尾的空白符忽略,因此空參數擴充為空白字串""(即使逗號之間有空白符)。
例:考慮TEST宏的標準c語言定義
#define TEST(a,b) printf(#a "<" #b "=%d/n", (a)<(b))
語句TEST(0,0xFFFF);TEST('/n', 10);展開如下:
printf("0" "<" "0xFFFF" "=%d/n", (0)<(0xFFFF));
printf("'//n'" "<" "10 "=%d/n", ('/n')<(10));
---------------------------------------------------------------
3.3.9 宏擴充中的記號合并 [C語言參考手冊,p38(r54)]
---------------------------------------------------------------
標準C語言中合并記號形成新記號時,由宏定義中的合并運算子##控制。重新掃描更多宏之前,宏替換表中任何運算子##中間的兩個記號合并成一個記號。因此必須有這種記號:##不能放在替換表開頭或末尾。如果合并之後得不到有效記號,則結果是未定義的。
例子:
#define TEMP(i) temp ## i
TEMP(1) = TEMP(2 + k) + x;
預先處理之後變成:
temp1 = temp2 + k + x;
上例中,擴充TEMP()+x時可能出現一個奇妙的情形。宏定義是有效,但##右邊沒有要組合的記號(除非遇到+,但這不是我們所要的)。要解決這個問題,應把正式參數i看成是專為##擴充的特殊的“空”記號。這樣,TEMP()+x擴充的結果將如我們預料的那樣為temp+x。
不能用記號拼接產生通用字元名。
和宏參數轉換成字串時一樣(見3.3.8節),編程人員可以利用許多非標準C語言實現中的漏洞獲得這種合并功能。儘管C語言的原始定義明確地把宏體描述成記號序列,而不是字元序列,但許多語言編譯器把宏體當作字元序列一樣擴充和重新掃描。這在編譯器處理備註陳述式時更加明顯,編譯器將備註陳述式完全刪除而不是換成空格,因此一些巧妙編寫的程式就可以利用這個特性。
例:考慮下列例子:
#define INC ++
#define TAB internal_table
#define INCTAB table_of_increments
#define CONC(x,y) x/**/y
CONC(INC,TAB)
標準C語言將CONC體解釋為兩個記號x和y,用空格分開(備註陳述式變成空格)。調用CONC(INC,TAB)擴充為兩個記號INC TAB。但有些非標準C語言實現直接刪除備註陳述式,然後重新掃描宏體中的記號,這樣就把CONC(INC,TAB)擴充為一個記號INCTAB;
-----------------------------------------------
步驟 標準C語言擴充 可能的非標準擴充
-----------------------------------------------
1 CONC(INC,TAB) CONC(INC,TAB)
2 INC/**/TAB INC/**/TAB
3 INC TAB INCTAB
4 ++ internal_table table_of_increments
測試代碼:
#define XVARNAME(i) x##i
#define PXVARNAME(n) printf("x"#n" = %d/n",x##n)
int k = 0;
int b = 0;
int XVARNAME(k)=12;
PXVARNAME(k + 1); //xk + 1 = 13
PXVARNAME(k); //xk = 12
b = XVARNAME(k) + 0;
printf("b = %d, k = %d/r/n", b, k); //b = 12, k = 0
b = XVARNAME(k + 10) + 0;
printf("b = %d, k = %d/r/n", b, k); //b = 22, k = 0
---------------------------------------------------------------
3.3.10 宏中的可變參數表 [C語言參考手冊,p38(r54)]
notice: Visual C++ 直至8.0版才開始支援C99的可變宏定義
---------------------------------------------------------------
#ifdef DEBUG
#define myprintf(...) fprintf(stderr, __VA_ARGS__)
#else
#define myprintf(...) fprintf(__VA_ARGS__)
#endif
特別地:
#define make_em_str(...) #__VA_ARGS__
下列調用
make_em_str(a,b,c,d)
展開成字串
"a,b,c,d"
-------------------------------------------------------------------------------------------------------------------------
題外話:
討厭得益網的積分增加方法,但是,那裡的有些東東確實不錯,如果您願意,幫忙點一下:
http://www.netyi.net
--------------------------------------------------------------------------------------------------------------------------