c語言中的預處理(2)

2021-06-09 12:58:22 字數 2764 閱讀 6717

在函式式巨集定義中,#運算子用於建立字串,#運算子後面應該跟乙個形參(中間可以有空格或tab),例如:

#define str(s) # s

str(hello world)

cpp命令預處理之後是"hello␣world",自動用"號把實參括起來成為乙個字串,並且實參中的連續多個空白字元被替換成乙個空格。

在巨集定義中可以用##運算子把前後兩個預處理token連線成乙個預處理token,和#運算子不同,##運算子不僅限於函式式巨集定義,變數式巨集定義也可以用。例如:

#define concat(a, b) a##b

concat(con, cat)

預處理之後是concat。再比如,要定義乙個巨集展開成兩個#號,可以這樣定義:

#define hash_hash # ## #
中間的##是運算子,巨集展開時前後兩個#號被這個運算子連線在一起。注意中間的兩個空格是不可少的,如果寫成####,會被劃分成####兩個token,而根據定義##運算子用於連線前後兩個預處理token,不能出現在巨集定義的開頭或末尾,所以會報錯。

我們知道printf函式帶有可變引數,函式式巨集定義也可以帶可變引數,同樣是在引數列表中用...表示可變引數。例如:

#define showlist(...) printf(#__va_args__)

#define report(test, ...) ((test)?printf(#test):\

printf(__va_args__))

showlist(the first, second, and third items.);

report(x>y, "x is %d but y is %d", x, y);

預處理之後變成:

printf("the first, second, and third items.");

((x>y)?printf("x>y"): printf("x is %d but y is %d", x, y));

在巨集定義中,可變引數的部分用__va_args__表示,實參中對應...的幾個引數可以看成乙個引數替換到巨集定義中__va_args__所在的地方。

呼叫函式式巨集定義允許傳空引數,這一點和函式呼叫不同,通過下面幾個例子理解空引數的用法。

#define foo() foo

foo()

預處理之後變成foofoo在定義時不帶引數,在呼叫時也不允許傳引數給它。

#define foo(a) foo##a

foo(bar)

foo()

預處理之後變成:

foobar

foo

foo在定義時帶乙個引數,在呼叫時必須傳乙個引數給它,如果不傳引數則表示傳了乙個空引數。

#define foo(a, b, c) a##b##c

foo(1,2,3)

foo(1,2,)

foo(1,,3)

foo(,,3)

預處理之後變成:

123

1213

3

foo在定義時帶三個引數,在呼叫時也必須傳三個引數給它,空引數的位置可以空著,但必須給夠三個引數,foo(1,2)這樣的呼叫是錯誤的。

#define foo(a, ...) a##__va_args__

foo(1)

foo(1,2,3,)

預處理之後變成:

1

12,3,

foo(1)這個呼叫相當於可變引數部分傳了乙個空引數,foo(1,2,3,)這個呼叫相當於可變引數部分傳了三個引數,第三個是空引數。

gcc有一種擴充套件語法,如果##運算子用在__va_args__前面,除了起連線作用之外還有特殊的含義,例如核心**net/netfilter/nf_conntrack_proto_sctp.c中的:

#define debugp(format, ...) printk(format, ## __va_args__)
printk這個核心函式相當於printf,也帶有格式化字串和可變引數,由於核心不能呼叫libc的函式,所以另外實現了乙個列印函式。這個函式式巨集定義可以這樣呼叫:debugp("info no. %d", 1)。也可以這樣呼叫:debugp("info")。後者相當於可變引數部分傳了乙個空引數,但展開後並不是printk("info",),而是printk("info"),當__va_args__是空引數時,##運算子把它前面的,號「吃」掉了。

原址:

c語言中的預處理(1)

剛接觸c語言的人都知道,每次主程式開始前都得寫乙個 include。但是卻不知道為什麼非要加這個東西,學了一段時間後,似乎會明白一點,但還是稀里糊塗的,在這裡,我們就把這玩意兒抽絲剝繭弄個明白。在c語言裡,有一種非常有用而又必不可少的部分,叫做預處理,說道這兒有人就笑了,不就是 include和 d...

C語言中的預處理命令

預處理指令 1.在源程式編譯之前,先進行一些特殊的預處理指令作解釋,產生乙個新的源程式 這個過程稱為編譯預處理 之後在進行通常的編譯。2.為了區別預處理指令和一般的c語言,所有預處理指令都是以 開頭,並且結尾無分號 3.預處理指令可以出現在程式的任何位置,它的作用範圍是從它出現的位置到檔案尾。4.c...

C 語言中的預處理命令

由於預處理命令不是 c 語言本身的組成部分,所以 c 編譯程式不能識別它們,也就不能直接對它們進行編譯,所以在 c 程式編譯之前,必須先對預處理命令進行處理,處理後程式中不再包括預處理命令了,再由編譯程式處理得到目標 c 語言提供的預處理命令共有三中 巨集定義,檔案包含和條件編譯,預處理命令以 開頭...