define 的高階用法

2021-07-03 12:28:57 字數 2578 閱讀 5572

原文:

一、linux c中用define定義可變引數的巨集

一般在除錯列印debug資訊的時候, 需要可變引數的巨集. 從c99開始可以使編譯器標準支援可變引數巨集(variadic macros), 另外gcc也支援可變引數巨集, 但是兩種在細節上可能存在區別.

1. __va_args__

__va_args__ 將 "..." 傳遞給巨集 . 如

#define debug(format, ...) fprintf(stderr, format, __va_args__)

2. gcc的複雜巨集

gcc使用一種不同的語法,從而可以給可變引數乙個名字,如同其它引數一樣.

#define debug(format, args...) fprintf (stderr, format, args)

這和第一條的巨集例子是完全一樣的,但是這麼寫可讀性更強並且更容易進行描述.

3. ##__va_args__

上面兩個定義的巨集,如果出現 debug("a message")的時候,由於巨集展開後有個多餘的逗號,所以將導致編譯錯誤.

為了解決這個問題,cpp 使用乙個特殊的"##"操作,格式如下:

#define debug(format, ...) fprintf (stderr, format, ## __va_args__)

這裡,如果可變引數被忽略或為空,"##"操作將使預處理器(preprocessor)去除掉它前面的那個逗號.

上文來自:

二、define巨集定義中的#,##,@#及\符號

1、# (stringizing)字串化操作符。

其作用是:將巨集定義中的傳入引數名轉換成用一對雙引號括起來引數名字串。其只能用於有傳入引數的巨集定義中,且必須置於巨集定義體中的引數名前。

如:#define example(instr) printf("the input string is:\t%s\n",#instr)

#define example1(instr) #instr

當使用該巨集定義時:

example(abc); 在編譯時將會展開成:printf("the input string is:\t%s\n","abc");

string str=example1(abc); 將會展成:string str="abc";

注意:對空格的處理

a。忽略傳入引數名前面和後面的空格。

如:str=example1(   abc ); 將會被擴充套件成 str="abc";

b.當傳入引數名間存在空格時,編譯器將會自動連線各個子字串,用每個子字串中只以乙個空格連線,忽略其中多餘乙個的空格。

如:str=exapme( abc    def); 將會被擴充套件成 str="abc def";

2、## (token-pasting)符號連線操作符

巨集定義中:引數名,即為形參,如#define sum(a,b) (a+b);中a和b均為某一引數的代表符號,即形式引數。

而##的作用則是將巨集定義的多個形參成乙個實際引數名。

如:#define examplenum(n) num##n

int num9=9;

使用:int num=examplenum(9); 將會擴充套件成 int num=num9;

注意:1.當用##連線形參時,##前後的空格可有可無。

如:#define examplenum(n) num ## n 相當於 #define examplenum(n) num##n

2.連線後的實際引數名,必須為實際存在的引數名或是編譯器已知的巨集定義

// preprocessor_token_pasting.cpp

#include 

#define paster( n ) printf_s( "token" #n " = %d", token##n )

int token9 = 9;

int main()

paster(9);

執行結果:

token9 = 9

3、@# (charizing)字元化操作符。

只能用於有傳入引數的巨集定義中,且必須置於巨集定義體中的引數名前。作用是將傳的單字元引數名轉換成字元,以一對單引用括起來。

#define makechar(x)  #@x

a = makechar(b);

展開後變成了:

a= 'b';

4、\ 行繼續操作符

當定義的巨集不能用一行表達完整時,可以用"\"表示下一行繼續此巨集的定義。

上文來自:

附:編譯器內建巨集(補充於2014.03.31)

ansi c標準中有幾個標準預定義巨集(也是常用的):

__line__:在源**中插入當前源**行號;

__file__:在原始檔中插入當前源檔名;

__date__:在原始檔中插入當前的編譯日期

__time__:在原始檔中插入當前編譯時間;

__stdc__:當要求程式嚴格遵循ansi c標準時該標識被賦值為1;

__cplusplus:當編寫c++程式時該識別符號被定義。

define巨集的高階用法

參考 普通巨集定義 define pi 3.14 編譯階段替換掉巨集 define t1 3 4 容易產生歧義 define t2 3 4 新增括號後,語義清楚 float r 1.0 float area pi r r int a 2 t1 巨集替換後變成 int a 2 3 4 不符合本意 in...

define巨集的用法

再舉乙個使用無引數巨集替代字串的例子 define m y y 3 y include int main define m y y 3 y 定義m表示式 y y 3 y 在編寫源程式時,所有的 y y 3 y 都可由m代替,而對源程式作編譯時,將先由預處理程式進行巨集代換,即用 y y 3 y 表示...

回憶 define的用法

ansi c規定 前可以有空格或者tab,和指令其餘部分之間也可以有空格,可以出現在任何地方,作用域從定義處到檔案結尾。因為預處理開始前,系統會刪除反斜線和換行符的組合,故可以把指令擴充套件到幾個物理行,這些物理行組成單個邏輯行。每個 define行 指邏輯的行 三部分組成 指令本身 巨集 替換列表...