宏妒御,(...)(#),(##),(__VA_ARGS__)用法

一直以來用宏定義#define也就是定義一些簡單的常量,至多也就是定義一個函數(shù)镇饺,很少關(guān)注宏定義的用法乎莉。直到看到這樣的代碼:

[cpp] view plain copy

#define PLAYSOUNDEFFECT(...) \

[[GameManager sharedGameManager] playSoundEffect:@#__VA_ARGS__]

這么強大的用法以前從來沒有想過〖轶裕看一下iOS Framework的一些頭文件惋啃,發(fā)現(xiàn)幾乎全部都是宏定義:

不得不說宏定義很強大!宏定義的使用使得程序的編寫更加的簡便监右!

作為iOS開發(fā)者边灭,有必要深入研究一下宏定義的用法。

最官方的關(guān)于宏的使用說明網(wǎng)址是:http://gcc.gnu.org/onlinedocs/cpp/Macros.html#Macros

在Apple的官網(wǎng)上可以找到GNU C 4.2 Preprocessor User Guide健盒,發(fā)現(xiàn)和GNU官網(wǎng)的說明一模一樣绒瘦。因為Xcode的編譯器就是基于GNU C 4.2預(yù)處理器宠互,因此在Objective-C的開發(fā)環(huán)境中使用宏和在C/C++中使用是一模一樣的。

下面的文字是閱讀官方使用說明后的總結(jié)及翻譯椭坚。(代碼直接從官方使用說明摘錄)

1予跌、Macros 宏

官方解釋:

A macro is a fragment of code which has been given a name. Whenever the name is used, it is replaced by the contents of the macro. There are two kinds of macros. They differ mostly in what they look like when they are used. Object-like macros resemble data objects when used, function-like macros resemble function calls.

有兩種宏的類型,一種是類對象的宏善茎,封裝使用的數(shù)據(jù)對象券册,另一種是類函數(shù)的宏,封裝函數(shù)的調(diào)用垂涯。在ObjC里面烁焙,那就是可以封裝Method的使用,如文章一開始的代碼

1.1 類對象的宏

最基本的使用:

[cpp] view plain copy

#define BUFFER_SIZE 1024

foo = (char *) malloc (BUFFER_SIZE);

foo = (char *) malloc (1024);

就是最基本的替換耕赘。

通常宏的名稱都是用大寫字母骄蝇。

------------------------------------------------------------------------------------------------

[cpp] view plain copy

#define NUMBERS 1, \

2, \

3

int x[] = { NUMBERS };

==> int x[] = { 1, 2, 3 };

在宏定義中,如果要換行操骡,使用“\"符號九火。然后經(jīng)預(yù)處理后還是在同一行。

------------------------------------------------------------------------------------------------

C預(yù)處理器是按順序讀取程序册招,因此宏定義生效在宏定義之后岔激。

[cpp] view plain copy

foo = X;

#define X 4

bar = X;

ces

foo = X;

bar = 4;

------------------------------------------------------------------------------------------------

宏調(diào)用時,預(yù)處理器在替換宏的內(nèi)容時是掰,會繼續(xù)檢測內(nèi)容本身是否也是宏定義虑鼎,如果是,會繼續(xù)替換內(nèi)容键痛。

[cpp] view plain copy

#define TABLESIZE BUFSIZE

#define BUFSIZE 1024

TABLESIZE

==> BUFSIZE

==> 1024

------------------------------------------------------------------------------------------------

宏定義以最后生效的定義為準炫彩,因此下面的代碼TABLESIZE對應(yīng)37

[cpp] view plain copy

#define BUFSIZE 1020

#define TABLESIZE BUFSIZE

#undef BUFSIZE

#define BUFSIZE 37

------------------------------------------------------------------------------------------------

如果宏定義內(nèi)容包含了名稱,則預(yù)處理器會終止展開防止無限嵌套(infinite resursion)

1.2 類函數(shù)宏

[cpp] view plain copy

#define lang_init()? c_init()

lang_init()

==> c_init()

類函數(shù)宏的名稱后面加了"()"絮短。

[cpp] view plain copy

#define lang_init ()? ? c_init()

lang_init()

==> () c_init()()

并且"()"必須緊隨在名稱后面否則就會認為是類對象宏江兢。

1.3 宏參數(shù)

在類函數(shù)宏里面可以添加參數(shù)使得更像真正的函數(shù)

[cpp] view plain copy

#define min(X, Y)? ((X) < (Y) ? (X) : (Y))

x = min(a, b);? ? ? ? ? ==>? x = ((a) < (b) ? (a) : (b));

y = min(1, 2);? ? ? ? ? ==>? y = ((1) < (2) ? (1) : (2));

z = min(a + 28, *p);? ? ==>? z = ((a + 28) < (*p) ? (a + 28) : (*p));

基本的使用和函數(shù)的定義類似,當然宏里面都是實際參數(shù)戚丸,用逗號隔開划址。預(yù)處理時扔嵌,先是將宏展開限府,然后將參數(shù)放進宏的主體中,再檢查一遍完整的內(nèi)容痢缎。

------------------------------------------------------------------------------------------------

如何宏里面有字符串的內(nèi)容胁勺,即使與參數(shù)名相同,也不會被替換独旷。如下:

[cpp] view plain copy

#define foo(x) x, "x"

foo(bar)? ? ? ? ==> bar, "x"

1.4 字符串化

使用”#“預(yù)處理操作符來實現(xiàn)將宏中的參數(shù)轉(zhuǎn)化為字符串署穗。例子如下:

[cpp] view plain copy

#define WARN_IF(EXP) \

do { if (EXP) \

fprintf (stderr, "Warning: " #EXP "\n"); } \

while (0)

WARN_IF (x == 0);

==> do { if (x == 0)

fprintf (stderr, "Warning: " "x == 0" "\n"); } while (0);

這個字符串化會將參數(shù)中的所有字符都實現(xiàn)字符串化寥裂,包括引號。如果參數(shù)中間有很多空格案疲,字符串化之后將會只用一個空格代替封恰。

然后沒有什么方法可以直接將參數(shù)轉(zhuǎn)化成單一的字符char

------------------------------------------------------------------------------------------------

[cpp] view plain copy

#define xstr(s) str(s)

#define str(s) #s

#define foo 4

str (foo)

==> "foo"

xstr (foo)

==> xstr (4)

==> str (4)

==> "4"

出現(xiàn)上面的結(jié)果是因為在使用str(s)時,s是字符串化褐啡,所以宏沒有擴展開诺舔。而使用xstr(s)時s作為一個參數(shù),因此先把宏完全擴展然后再放進參數(shù)备畦。

1.5 連接

使用"##"操作符可以實現(xiàn)宏中token的連接低飒。

[cpp] view plain copy

struct command

{

char *name;

void (*function) (void);

};

struct command commands[] =

{

{ "quit", quit_command },

{ "help", help_command },

...

};

#define COMMAND(NAME)? { #NAME, NAME ## _command }

struct command commands[] =

{

COMMAND (quit),

COMMAND (help),

...

};

如上,使參數(shù)NAME對應(yīng)的字符與_command連接起來懂盐,而不進行其他轉(zhuǎn)化褥赊。當然要注意連接后的字符必須是有意義的,否則只會出現(xiàn)錯誤或警告莉恼。

然后C預(yù)處理器會將注釋轉(zhuǎn)化成空格拌喉,因此在宏中間,參數(shù)中間加入注釋都是可以的俐银。但不能將"##"放在宏的最后司光,否則會出現(xiàn)錯誤。

1.6 多參數(shù)宏(Variadic Macros)

[cpp] view plain copy

#define eprintf(...) fprintf (stderr, __VA_ARGS__)

eprintf ("%s:%d: ", input_file, lineno)

==>? fprintf (stderr, "%s:%d: ", input_file, lineno)

使用標識符__VA_ARGS_來表示多個參數(shù)悉患,在宏的名稱中則使用(...)

在C++中也可以使用如下的方式:

[cpp] view plain copy

#define eprintf(args...) fprintf (stderr, args)

結(jié)果是一樣的残家。

------------------------------------------------------------------------------------------------

"##"的特殊用法:

[cpp] view plain copy

#define eprintf(format, ...) fprintf (stderr, format, ##__VA_ARGS__)

eprintf ("success!\n")

==> fprintf(stderr, "success!\n");

將"##"放在","和參數(shù)之間,那么如果參數(shù)留空的話售躁,那么"##"前面的","就會刪掉坞淮,從而防止編譯錯誤。

1.7 取消或重新宏定義

這個看下面的代碼就明白:

[cpp] view plain copy

#define FOO 4

x = FOO;? ? ? ? ==> x = 4;

#undef FOO

x = FOO;? ? ? ? ==> x = FOO;

These definitions are effectively the same:

#define FOUR (2 + 2)

#define FOUR? ? ? ? (2? ? +? ? 2)

#define FOUR (2 /* two */ + 2)

but these are not:

#define FOUR (2 + 2)

#define FOUR ( 2+2 )

#define FOUR (2 * 2)

#define FOUR(score,and,seven,years,ago) (2 + 2)

對于重定義陪捷,如果定義的宏不一樣回窘,那么編譯器會給出警告并使用最新定義的宏。

通過上面的總結(jié)描述市袖,現(xiàn)在就可以輕松看到本文開始的宏定義的含義了啡直。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市苍碟,隨后出現(xiàn)的幾起案子酒觅,更是在濱河造成了極大的恐慌,老刑警劉巖微峰,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件舷丹,死亡現(xiàn)場離奇詭異,居然都是意外死亡蜓肆,警方通過查閱死者的電腦和手機颜凯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門谋币,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人症概,你說我怎么就攤上這事蕾额。” “怎么了彼城?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵凡简,是天一觀的道長。 經(jīng)常有香客問我精肃,道長秤涩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任司抱,我火速辦了婚禮筐眷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘习柠。我一直安慰自己匀谣,他們只是感情好,可當我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布资溃。 她就那樣靜靜地躺著武翎,像睡著了一般。 火紅的嫁衣襯著肌膚如雪溶锭。 梳的紋絲不亂的頭發(fā)上宝恶,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天,我揣著相機與錄音趴捅,去河邊找鬼垫毙。 笑死,一個胖子當著我的面吹牛拱绑,可吹牛的內(nèi)容都是我干的综芥。 我是一名探鬼主播,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼猎拨,長吁一口氣:“原來是場噩夢啊……” “哼膀藐!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起红省,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤额各,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后类腮,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體臊泰,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年蚜枢,在試婚紗的時候發(fā)現(xiàn)自己被綠了缸逃。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡厂抽,死狀恐怖需频,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情筷凤,我是刑警寧澤昭殉,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站藐守,受9級特大地震影響挪丢,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜卢厂,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一乾蓬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧慎恒,春花似錦任内、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至粒氧,卻和暖如春越除,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背外盯。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工廊敌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人门怪。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓骡澈,卻偏偏與公主長得像,于是被迫代替她去往敵國和親掷空。 傳聞我的和親對象是個殘疾皇子肋殴,可洞房花燭夜當晚...
    茶點故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 1,Search Bar 怎樣去掉背景的顏色(storyboard里只能設(shè)置background顏色,可是發(fā)現(xiàn)cl...
    以德扶人閱讀 2,368評論 2 50
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理坦弟,服務(wù)發(fā)現(xiàn)护锤,斷路器,智...
    卡卡羅2017閱讀 134,699評論 18 139
  • C中的預(yù)編譯宏定義 2009-02-10 作者: infobillows 來源:網(wǎng)絡(luò) 在將一個C源程序轉(zhuǎn)換為可執(zhí)行...
    白水灬煮一切閱讀 1,607評論 0 5
  • 宏定義在C系開發(fā)中可以說占有舉足輕重的作用酿傍。底層框架自不必說烙懦,為了編譯優(yōu)化和方便,以及跨平臺能力赤炒,宏被大量使用氯析,可...
    你好自己閱讀 1,054評論 0 5
  • 文/孟小滿 因為懂得你的癡心掩缓,所以拒絕這份只是感動的感情雪情。 2017.9.5 星期二 ...
    孟小滿閱讀 1,460評論 89 76