C 中的巨集替換

2021-07-11 19:43:40 字數 2878 閱讀 9963

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 簡化程...