1.引子
#define cat(x, y) x ## y
那麼cat(a, b)和cat(cat(a, b), c)的結果是啥.
#define str_impl(x) #x
#define str(x) str_impl(x)
的意圖何在.
2.規則
巨集替換是c/c++的預處理中的一部分,在c++標準中有4條規則來定義替換.
規則1:實參替換.
本條規則描述帶引數的巨集的替換過程.
對於巨集定義中的形參,在替換列表中,如果不是作為#或##的運算元,那麼將對應實參完全
展開(相當於對實參進行求值),然後將替換列表中的形參替換掉.如果是#或##的運算元,
那麼不進行替換.
規則2:多次掃瞄.
在所有的形參替換為實參後,對結果進行再次掃瞄,如果發現還有可替換的巨集,則進行替換,
否則中止.
規則3:遞迴替換抑制.
如果在替換列表中發現當前正在展開的巨集的名字,那麼這裡不進行替換.更進一步,在巢狀
的替換過程中發現已經替換過的巨集的名字,則不進行替換.
規則4:遞迴預處理抑制.
如果替換後的結果形成預處理指令,則不執行這條預處理指令.
3.例項
#define cat(x, y) x ## y
在cat(cat(a, b), c)中,首先掃瞄替換列表,發現x和y兩個形參作為##的運算元,那麼直接
將實參不作任何處理地搬過來,並進行連線運算,得到結果是cat(a, b)c
若在此基礎上增加
#define xcat(x, y) cat(x, y)
在xcat(xcat(a, b), c)中首先對x進行求值,也就是先計算xcat(a, b)的結果,容易得到
值是ab.然後對y進行求值,發現不必進行任何處理,值是c,得到結果cat(ab, c).
然後應用規則2,對cat(ab, c)進行求值,容易得到結果是abc.
顯然#define str_impl(x) #x
#define str(x) str_impl(x)
的意圖在於防止#阻止巨集作為引數的時候被規則1阻止展開.
再看幾個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\0d", "abc", 』\4』) /* this goes away */
== 0) str(: @\n), 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" ": @\n", 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"了.
python 巨集替換 和 在巨集替換中的作用
include define f a,b a b define g a a define h a g a int main printf s n h f 1,2 printf s n g f 1,2 return 0 首先需要了解 和 的意義。將右邊的引數做整體的字串替換。define g a a ...
C語言巨集替換
當乙個巨集引數被放進巨集體時,這個巨集引數會首先被全部展開 有例外,見下文 當展開後的巨集引數被放進巨集體時,預處理器對新展開的巨集體進行第二次掃瞄,並繼續展開。例如 define param x x define addparam x int x param addparam 1 因為addpar...
python巨集替換 簡單的巨集替換
簡單的巨集替換 1.巨集定義必須寫在第一次使用該巨集定義的 之前 2.巨集定義不是以分號結束的 3.define string1 string2 之間至少要有乙個空格 4.string 1稱為巨集,string2 稱為巨集擴充套件 5.巨集名用大寫的字母表示是乙個習慣 6.使用巨集的好處 a 簡化程...