宏交換C語言
A. C語言中,宏替換的替換規則
簡單來說:宏定義又稱為宏代換、宏替換,簡稱「宏」。宏替換是C/C++的預處理中的一部分,在C++標准中有4條規則來定義替換。
規則1:實參替換。
本條規則描述帶參數的宏的替換過程。
對於宏定義中的形參,在替換列表中,如果不是作為#或##的操作數,那麼將對應實參完全
展開(相當於對實參進行求值),然後將替換列表中的形參替換掉.如果是#或##的操作數,
那麼不進行替換。
規則2:多次掃描。
在所有的形參替換為實參後,對結果進行再次掃描,如果發現還有可替換的宏,則進行替換,
否則中止。
規則3:遞歸替換抑制。
如果在替換列表中發現當前正在展開的宏的名字,那麼這里不進行替換.更進一步,在嵌套
的替換過程中發現已經替換過的宏的名字,則不進行替換。
規則4:遞歸預處理抑制。
如果替換後的結果形成預處理指令,則不執行這條預處理指令。
看幾個C++標准中的例子:
#define x 3
#define f(a) f(x * (a))
#undef x
#define x 2
#define g f
#define z z[0]
#define h g(~
#define m(a) a(w)
#define w 0,1
#define t(a) a
f(y+1) + f(f(z)) % t(t(g)(0) + t)(1);
g(x+(3,4)-w) | h 5) & m(f)^m(m);
其結果分別是
f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);
f(2 * (2+(3,4)-0,1)) | f(2 * ( ~ 5)) & f(2 * (0,1))^m(0,1);
對於第一個,主要在於t(t(g)(0) + t)(1)的展開。
容易計算出最外層的t的實參是f(2 * (0)) + t,而作為t的參數傳入時其中的t是
正在被展開的宏,所以根據規則3,不對這個t進行處理,保持不變,得到f(2 * (0)) + t(1)。
對於第二個,h 5)被替換為g(~5),應用規則2,被替換為f(2 * ( ~ 5))。
而m(m)首先被替換為m(w),然後應用規則2再次進行替換,但是m已經是替換過的了,所以保持
不變,只對w進行替換。
#define str(s) # s
#define xstr(s) str(s)
#define debug(s, t) printf("x" # s "= %d, x" # t "= %s",
x ## s, x ## t)
#define INCFILE(n) vers ## n /* from previous #include example */
#define glue(a, b) a ## b
#define xglue(a, b) glue(a, b)
#define HIGHLOW "hello"
#define LOW LOW ", world"
debug(1, 2);
fputs(str(strncmp("abc d", "abc", 』4』) /* this goes away */
== 0) str(: @ ), s);
#include xstr(INCFILE(2).h)
glue(HIGH, LOW);
xglue(HIGH, LOW)
其結果分別是
printf("x" "1" "= %d, x" "2" "= %s", x1, x2);
fputs("strncmp("abc\0d", "abc", 』\4』) = = 0" ": @ ", s);
#include "vers2.h"
"hello";
"hello" ", world"
關鍵是glue和xglue.
對於glue(HIGH, LOW),首先有一個規則1的抑制,得到HIGHLOW;的結果,然後二次掃描,得到
"hello";
對於xglue(HIGH, LOW)沒有抑制效果,所以對參數求值,分別得到HIGH和LOW ", world",即
glue(HIGH, LOW ", world")。
然後進行連接操作得到HIGHLOW ", world",最後再掃描一次得到"hello" ", world"
如果考慮字元串的自然的連接,就可以得到"hello, world"了。
(1)宏交換C語言擴展閱讀
宏語言是一類編程語言,其全部或多數計算是由擴展宏完成的。宏語言並未在通用編程中廣泛使用,但在文本處理程序中應用普遍。例如, C preprocessor C預處理器Internet Macros(iOpus) M4(如前所述,源於AT&T,捆綁於Unix)
宏定義
c程序提供的預處理功能之一。包括帶參數的宏定義和不帶參數的宏定義。具體是指用一個指定的標志符來進行簡單的字元串替換或者進行闡述替換。形式為:
#define標志符[(參數表)] 字元串
宏名
在上定義中的標志符被稱為「宏名」。
宏展開
在c程序編譯時將宏名替換成字元串的過程稱為「宏展開」。
宏語言是一類編程語言,其全部或多數計算是由擴展宏完成的。宏語言並未在通用編程中廣泛使用, 但在文本處理程序中應用普遍。例如,
C preprocessorC 預處理器
Internet Macros(iOpus)
M4(如前所述,源於AT&T,捆綁於Unix)