Xcode 中關於"#"的小知識

在代碼中使用Autolayout時,你們都會使用NSDictionaryOfVariableBindings這個宏,這個宏能夠生成一個變量名到變量值映射的Dictionary。好比NSDictionaryOfVariableBindings(button1, button2)將會生成一個{ @"button1" = button1, @"button2 = button2 }的Dictionary。它是怎麼作到的呢?咱們來看看這個宏的定義:xcode

#define NSDictionaryOfVariableBindings(...) _NSDictionaryOfVariableBindings(@"" # __VA_ARGS__, __VA_ARGS__, nil)

這個宏定義中有3個參數,後兩個參數不難理解,但第一個參數中間有個#符號,語法上看起來比較怪異,這個是什麼呢?之前在作越獄的mobilesubstrate開發時,其中定義的一堆宏頻繁使用了這個符號,下面就來揭開#這個符號在宏定義中的迷霧。函數

預編譯的一些知識

咱們的代碼在build時並非直接進行編譯的,在編譯以前還進行了預編譯處理。預編譯會把include或import的文件導入到文件中,同時會將代碼中用到的宏進行替換。注意宏是直接在代碼中替換成宏的定義的,若是有嵌套也會逐層替換。ui

「#」指示一些預編譯命令

預編譯命令通常都是以#開頭的,好比#include#import#if等,在這裏就不一一說明了,本文主要說明一下#在宏定義裏面的一些做用。code

宏參數字符串化

在一個參數前加一個#,預處理時將會變成這個參數名的字符串常量,即字符串化(stringify)。好比:orm

#define GET_NAME(X) #X
int a = 0;
NSLog(@"%s",GET_NAME(a));      //output: "a"
NSLog(@"%s",GET_NAME(a+3));    //output: "a+3"

將會獲得如下輸出:blog

a
a+3

能夠看出#,將參數原樣轉換成字符串常量,若是參數是一個表達式,那麼輸出這個表達式的原樣字符串常量。開發

回頭再看看NSDictionaryOfVariableBindings的定義:字符串

#define NSDictionaryOfVariableBindings(...) _NSDictionaryOfVariableBindings(@"" # __VA_ARGS__, __VA_ARGS__, nil)

若是這樣生成兩個button的映射:get

NSDictionaryOfVariableBindings(button1, button2);

那麼預編譯時就會轉換成:string

_NSDictionaryOfVariableBindings(@"""button1, button2", button1, button2, nil);

因爲兩個常量字符串放在一塊兒就是字符串常量串聯,將變成兩個字符串常量組合在一塊兒的字符串常量,也就是上面是一個空字符串"""button1, button2"串聯,因此上面的代碼等價於:

_NSDictionaryOfVariableBindings(@"button1, button2", button1, button2, nil);

那麼_NSDictionaryOfVariableBindings函數就能夠將它的第一個參數按逗號,分割開做爲key,後面就是各個key對應的值了。所以這段代碼就建立了一個內容爲{ @"button1" = button1, @"button2 = button2 }的Dictionary。

命名的串聯

#在宏定義中的另外一個做用就是用於命名的串聯,用##就能夠串聯它左右兩邊的命名,好比如下代碼:

#define CONCAT(X, Y) X ## Y
NSString *helloworld = @"Hello, world!";
NSLog(@"%@",CONCAT(hello, world)); //output: "Hello, world"

CONCAT(hello, world)實際被轉換成helloworld。注意一下,由於宏是預編譯階段進行展開的,就是說在編譯以前,所以代碼中的helloworld即便沒有定義其實也是沒問題的,預編譯處理後,這兩個命名是不存在的。

可選可變參數

##在宏定義中能夠放在__VA_ARGS__以前表示可變參數能夠爲空,不然的話可變參數至少爲一個了。

#define MYLOG(format, ...) NSLog(format, ##__VA_ARGS__)
MYLOG(@"Don't make an error!");

上面代碼中MLOG中只有一個參數,若是不加##,則MLOG至少須要兩個參數,在Xcode裏將會出現編譯錯誤。

 

轉自:http://blog.xcodev.com/blog/2013/12/16/mists-of-the-sharp/

相關文章
相關標籤/搜索