iOS中宏的入門和實戰(zhàn)

最近新加入了項目組举塔,看到了一個讓我很費解的宏定義

#define ServiceTypeMake(_cls, _sel) (NO && ((void)[_cls _sel[Service new]], NO),\ [NSString stringWithFormat:@"%s.%s", #_cls, #_sel])

去掉一些敏感信息后的宏就是這個樣子艇炎。看到這個宏之后陵吸,根據(jù)我之前的經(jīng)驗只曉得[NSString stringWithFormat:@"%s.%s", #_cls, #_sel]這塊是字符串拼接民鼓,前半部分目測像寫了個廢話(NO &&結(jié)果明顯是NO啊!5愣睢!)莺琳。

ServiceTypeMake(IDUrlService, sendUrlRequest:)

預(yù)編譯展開后就是這樣的:

(__objc_no && ((void)[IDUrlService sendUrlRequest:[Service new]], __objc_no), [NSString stringWithFormat:@"%s.%s", "IDUrlService", "sendUrlRequest:"])

&&短路與还棱,前面判斷為假后面就不執(zhí)行了,最后相當(dāng)于就是個字符串拼接惭等,所以這個宏的寫法我覺得不是很能理解珍手。通過查閱一些資料和文章后,我對iOS中宏的定義和使用有了一些深入的了解辞做,希望大家指正琳要。


1.宏的入門

?*宏的定義

任何中文的翻譯都不夠權(quán)威,這里摘抄一下GCC對宏的定義(定義鏈接):

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.

You may define any valid identifier as a macro, even if it is a C keyword.? The preprocessor does not know anything about keywords.? Thiscan be useful if you wish to hide a keyword such as const from an older compiler that does not understand it.? However, the preprocessor operator defined(see Defined) can never be defined as amacro, and C++’s named operators (see C++ Named Operators) cannot be macros when you are compiling C++.

從定義中可以知道宏分兩種對象宏(Object-like?macros)和方法宏(function-like?macros)秤茅,接下來一一介紹稚补。

對象宏(Object-like macros)

這里先舉一些??:

#define BUFFER_SIZE 1024

#define NUMBERS 1, \

??????????????????????????????? + 2, \

??????????????????????????????? + 3

#define NUMBER_TOTAL?NUMBERS

看上面這些例子可以總結(jié)出以下東西:

1.在定義宏的時候,宏的名字通常都會使用大寫字母框喳,目的是方便大家一眼就能看出這是個宏课幕,引用的GCC原文是:

By convention, macro names are written in uppercase. Programs are

easier to read when it is possible to tell at a glance which names are

macros.

2.如果一個宏的定義中需要換行的話可以用反斜杠“\”結(jié)尾來斷行

3.在調(diào)用宏時厦坛,預(yù)處理器在替換宏的內(nèi)容時會繼續(xù)檢查宏的內(nèi)容本身是否也是宏定義,如果是乍惊,會繼續(xù)替換宏定義的內(nèi)容杜秸,直到全部展開。

這里可能會有一點疑問润绎,就是對于自引用宏的處理撬碟,先舉個例子:

#define FOO (4 + FOO)

這要是在使用中要一直展開的話就會是一個無限遞歸的過程,GCC中有對這種情況進行處理凡橱,只會在使用FOO的地方替換成(4 + FOO)小作,還有一種情況是:

#define x (4 + y)

#define y (2 * x)

這里會展開為如下形式:

x → (4 + y)

? ? → (4 + (2 * x))

y? ? → (2 * x)

? ? → (2 * (4 + y))

4.宏定義以最后有效的定義為準,例如

#define FOO 4

#undef FOO

#define FOO 5

NSLog(@"%d", FOO);? ? ?→ 5

方法宏(function-like macros)

方法宏的特點是在定義宏的時候宏的名字后會接著一對括號稼钩,如:

#define MAX(a, b) ((a) > (b))

這里也有一些注意點:

1.重中之重顾稀,就是有參數(shù)的時候在表達式里盡量多加括號(防御式編程),避免一些操作符優(yōu)先級問題造成結(jié)果錯誤:

#define MULTIP(a, b) a * b

NSLog(@"%d", MULTIP(1+2, 3+4));? ? ?→11

MULTIP(1+2, 3+4)

????????? →1+2? *? 3+4

?????????????????? →11

2.如果有字符串內(nèi)容坝撑,即使與參數(shù)名稱相同也不會被替換

#define func(x) x, @"x"

NSLog(@"%@,%@", func(@"abc")); // 輸出結(jié)果為 abc,x

3.使用"#"預(yù)處理操作符來實現(xiàn)將宏中的參數(shù)轉(zhuǎn)化為字符(串)静秆,這個操作會將參數(shù)中的所有字符都實現(xiàn)字符(串)話,包括引號巡李。(有的文章里面說會把參數(shù)里面的多個空格替換為一個空格抚笔,親測不會)

#define XSTR(s) STR(s)

#define STR(x) #x

#define FOO @"? ? a? ? ? b? ? cc"

NSLog(@"%s", STR(FOO));? ? //輸出FOO

NSLog(@"%s", XSTR(FOO));? ?//輸出@"? ? a? ? ? b? ? cc"

4.使用"##"實現(xiàn)宏中token的連接

#define VIEW(prefix/*前綴*/, suffix/*后綴*/) prefix##View##suffix

VIEW(UI,) ? ? ? ? ? ? ? ? // 等價于 UIView

VIEW(UI, Controller) ? ? // 等價于 UIViewController

示例所示表示把prefix和suffix對應(yīng)的內(nèi)容與View連接起來,當(dāng)然連接后的字符(串)必須是有意義的侨拦,否則會出現(xiàn)錯誤或警告殊橙;但不能將 “##” 放在宏的最后,否則會出現(xiàn)錯誤狱从。

預(yù)處理器會將注釋轉(zhuǎn)化成空格膨蛮,因此在宏中間,參數(shù)中間加入注釋都是可以的季研。只能加入/**/這種注釋而不能加入//這種敞葛。

“##”的特殊用法:

#define NSLog(args, ...) NSLog(args, ##__VA_ARGS__);

NSLog(@"abc") ? ? ? ? ? ? ? ?// 輸出結(jié)果為 abc

NSLog(@"123, "@"abc") ? ?// 輸出結(jié)果為 123, abc

將 “##” 放在 "," 和參數(shù)之間,那么如果參數(shù)留空的話与涡,那么 “##” 前面的 "," 就會刪掉惹谐,從而防止編譯錯誤。

上例中使用標識符 __VA_ARGS__ 來表示多個參數(shù)驼卖,在宏的定義中則使用 (...) 表示氨肌。

經(jīng)過上面這些內(nèi)容,大家對宏的使用已經(jīng)有了基本的認識酌畜,但在實際使用過程中依然還有很多坑(特別是函數(shù)宏)怎囚,只有多使用和學(xué)習(xí),才能慢慢達到掌握的水準檩奠,我們要開始踩坑之旅了桩了。

1.MIN

我們很快會得出我們的版本:

#define MIN_(a, b) ((a) < (b) ? (a) : (b))

測試一下:

初級版:

NSLog(@"%d",MIN_(3,5));

//=>NSLog(@"%d", ((3) < (5) ? (3) : (5)));

//=>3

高級版:

?NSLog(@"%d",MIN_(2+6,3*4));

//=>NSLog(@"%d", ((2+6) < (3*4) ? (2+6) : (3*4)));

//=>8

測試通過附帽,發(fā)布上線!>蕉扮!


開心!?攀ァ喳钟!

項目上線了,跑的沒問題在岂,直到有一天一個特殊的情況出現(xiàn)了:

?NSInteger a = 5;

?NSInteger b = 2;

NSInteger c = MIN_(a, b++);

NSLog(@"a = %d, b = %d, c = %d", a, b, c); //輸出a = 5 , b = 4, c = 3;

一臉懵逼奔则,這不是真的~


what???

我們期望的結(jié)果是a = 5,b = 3蔽午, c = 2易茬,a是5,b是2及老,b++先取b的值跟a比抽莱,比a小,所以c得值是2骄恶,b自增1食铐,最后b的值是3,這才是想要的結(jié)果嘛僧鲁。為啥會出現(xiàn)上面的結(jié)果呢虐呻,不妨展開一下

NSInteger c?= MIN_(a, b++) = ((a) < (b++) ? (a) : (b++));

這里a先跟b比,5比2大寞秃,b會自增1斟叼,b為3,此時c取b得值為3蜕该,接著b會再自增1犁柜,為4洲鸠。問題就出在比較完a堂淡,b的值后b進行了自增1的操作。這里小括號已經(jīng)無法解決這個問題了扒腕,我們需要借助GNU C的賦值擴展({...})绢淀,使用這樣的方法可以計算出一個對象,而且不會浪費變量名瘾腰,可以在小范圍的作用域內(nèi)計算特殊的值

NSInteger x = ({

? ? ? ? NSInteger y = 2;

? ? ? ? NSInteger z = 3;

? ? ? ? y + z;

? ? });

? ? NSInteger y = 4; //繼續(xù)使用y皆的,z當(dāng)變量沒問題

? ? NSInteger z = 5;

有了這個擴展,我們就能解決MIN的寫法問題了蹋盆,GNU C中MIN的標準寫法是

#define?MIN(A,B)?({?__typeof__(A)?__a?=?(A);\

?__typeof__(B)?__b?=?(B);\

?__a?<?__b???__a?:?__b;?})

賦值擴展里包含3個語句费薄,前兩個定義了兩個變量__a和__b其類型為輸出參數(shù)的類型硝全,再進行取小值得運算。用這個寫法試了下完美解決問題楞抡,但依然會有坑伟众。

NSInteger __a = 5;

NSInteger __b =2;

NSInteger __c =MIN_(__a, __b++);

NSLog(@"__a =%d, __b = %d, __c = %d", __a, __b, __c); //輸出__a = 5, __b = 2, __c = 0

因為賦值函數(shù)內(nèi)變量名與外部變量名重名而造成無法被初始化,造成宏的行為不可預(yù)知召廷。Apple的工程師徹底解決了這個問題凳厢,官方的寫法是

#define __NSX_PASTE__(A,B) A##B

#if !defined(MIN)

? ? #define __NSMIN_IMPL__(A,B,L) ({ __typeof__(A) __NSX_PASTE__(__a,L) = (A); __typeof__(B) __NSX_PASTE__(__b,L) = (B); (__NSX_PASTE__(__a,L) < __NSX_PASTE__(__b,L)) ? __NSX_PASTE__(__a,L) : __NSX_PASTE__(__b,L); })

? ? #define MIN(A,B)? __NSMIN_IMPL__(A, B, __COUNTER__)

#endif

__NSX_PASTE__這個宏是用來做字符串拼接,?__NSMIN_IMPL__這個宏除了字符串拼接之外跟之前的宏寫法完全一樣竞慢,比較費解的就是__NSMIN_IMPL__(A, B, __COUNTER__)這里第三個參數(shù)__COUNTER__先紫,__COUNTER__是預(yù)定義的宏,在編譯階段開始時從0開始計數(shù)筹煮,每次被使用時加1遮精,這樣就大大避免了變量名重名的可能性。如果一定要任性的定義變量名為__a234這樣的名字败潦,后果只會是"no zuo, no die"仑鸥。

2.NSLog

通過打印來調(diào)試是我們經(jīng)常使用的一種方式,我們希望測試的時候多輸出一些信息变屁,比如所在行眼俊、方法名等,在release環(huán)境下不打印信息粟关,通常我們的寫法會是

#ifdef DEBUG

#defineNSLog(format, ...) do {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \

fprintf(stderr,"<%s : %d> %s\n",? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \

[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String],? \

__LINE__, __func__);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \

(NSLog)((format), ##__VA_ARGS__);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \

fprintf(stderr,"-------\n");? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \

} while (0)

#else

#define NSLog(...);

#endif

這個宏定義比較復(fù)雜了疮胖,首先判斷是否定義了DEBUG,就是說是否在DEBUG模式下闷板,我們按住command點擊一下并找不到定義的位置澎灸,那DEBUG在哪里定義的呢??在 "Target > Build Settings > Preprocessor Macros > Debug" 里有一個"DEBUG=1"遮晚。在沒打包的情況下性昭,就屬于DEBUG模式。再看宏定義县遣,先拋開do{}while(0)糜颠,看內(nèi)部。首先會打印文件路徑的最后一個路徑萧求,還有行數(shù)和調(diào)用的方法其兴。這里出現(xiàn)了__FILE__, __LINE__, __func__三個預(yù)定義宏,具體的作用大家可以參考預(yù)定義宏夸政。接著是一個標準的NSLog調(diào)用元旬,輸出參數(shù)信息,最后在打印一排“------------”并換行。這里比較費解的就是外層的這個do{}while(0)的作用了匀归,貌似沒啥用坑资,就是讓代碼執(zhí)行一次,那我們可不可以去掉do()while(0)把NSLog寫成這樣

#defineNSLog(format, ...)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \

fprintf(stderr,"<%s : %d> %s\n",? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \

[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String],? \

__LINE__, __func__);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \

(NSLog)((format), ##__VA_ARGS__);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \

fprintf(stderr,"-------\n");? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \

NSLog(@"aaa");

這個例子里我們可以正常輸出了穆端,但如果我們碰到這樣的呢

if(1)

? ? ? ? NSLog(@"aaa");

這里首先出現(xiàn)了一種反面的寫法盐茎,就是if條件語句判斷后不帶大括號。我們先看看程序預(yù)編譯之后的結(jié)果

if (1)

? ? ? ? fprintf(__stderrp,"<%s : %d> %s\n", [[[NSString stringWithUTF8String:"/Users/baidu/Desktop/test/TestMacro/TestMacro/ViewController.m"] lastPathComponent] UTF8String],98, __func__); (NSLog)((@"aaa")); fprintf(__stderrp,"-------\n");;

我們知道if判斷不帶大括號的寫法是只會執(zhí)行判斷條件后面的一個語句徙赢,雖然這里執(zhí)行完后好像對結(jié)果沒什么影響字柠,我們還是覺得是不是加個大括號更好一點,就有了一個高級點的版本

#defineNSLog(format, ...) {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \

fprintf(stderr,"<%s : %d> %s\n",? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \

[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String],? \

__LINE__, __func__);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \

(NSLog)((format), ##__VA_ARGS__);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \

fprintf(stderr,"-------\n");? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \

}

這樣看著就沒什么毛病了狡赐,還減少了do()while(0)的執(zhí)行窑业,減少了點點CPU的消耗,很開森枕屉!很明顯常柄,事情不會這么簡單,總有童鞋會有“新奇”的寫法

if(1)

? ? ? ? NSLog(@"aaa");

? ? else

? ? ? ? NSLog(@"bbb");

這么寫了一下搀擂,編譯都會報錯西潘,wtf???看下預(yù)編譯的結(jié)果

if (1)

? ? ? ? { fprintf(__stderrp,"<%s : %d> %s\n", [[[NSString stringWithUTF8String:"/Users/baidu/Desktop/test/TestMacro/TestMacro/ViewController.m"] lastPathComponent] UTF8String],98, __func__); (NSLog)((@"aaa")); fprintf(__stderrp,"-------\n"); };

? ? else

? ? ? ? { fprintf(__stderrp,"<%s : %d> %s\n", [[[NSString stringWithUTF8String:"/Users/baidu/Desktop/test/TestMacro/TestMacro/ViewController.m"] lastPathComponent] UTF8String],100, __func__); (NSLog)((@"bbb")); fprintf(__stderrp,"-------\n"); };

細心的同學(xué)應(yīng)該會發(fā)現(xiàn)if判斷的大括號后居然多了一個“;”哨颂,這個“喷市;”哪里來的呢,是NSLog(@"aaa");這里出來的威恼,就報錯了品姓。在試試加了do{}while(0)的版本呢,編譯一下看看區(qū)別

if (1)

? ? ? ? do{ fprintf(__stderrp,"<%s : %d> %s\n", [[[NSString stringWithUTF8String:"/Users/baidu/Desktop/test/TestMacro/TestMacro/ViewController.m"] lastPathComponent] UTF8String],98, __func__); (NSLog)((@"aaa")); fprintf(__stderrp,"-------\n"); }while(0);

? ? else

? ? ? ? do{ fprintf(__stderrp,"<%s : %d> %s\n", [[[NSString stringWithUTF8String:"/Users/baidu/Desktop/test/TestMacro/TestMacro/ViewController.m"] lastPathComponent] UTF8String],100, __func__); (NSLog)((@"bbb")); fprintf(__stderrp,"-------\n"); }while(0);

咦箫措,一下就不一樣了腹备,do{}while(0)完美的利用上了最后的分號。事實上斤蔓,在編譯器編譯階段植酥,遇到do{}while(0)時會做一些優(yōu)化,執(zhí)行的時間并不會變多弦牡。從這里我們總結(jié)出來兩點

(1)在宏展開有多個語句時友驮,可以包裹上do{}while(0)來吃掉“;”

(2)不要出現(xiàn)if判斷不帶{}的寫法,貌似簡化了一點喇伯,事實上往往會害人害己喊儡,出現(xiàn)一些莫名其妙的異常拨与。

在我們平時遇到的宏中還有很多更復(fù)雜稻据、更有趣的宏。首先不要謊,可以先將其展開來慢慢分析捻悯,通過一點點琢磨匆赃,會理解其精髓的。最后提一下iOS中怎么進行預(yù)編譯查看結(jié)果

1.點擊輔助編輯按鈕


2.點擊出現(xiàn)的這個按鈕

3.選擇下拉中出現(xiàn)的Preprocess選項今缚,就會出現(xiàn)編譯結(jié)果算柳。

《宏的入門和理解》就到這里了,之后有時間還會在分享一些更復(fù)雜的宏姓言。??


參考文章:

1.GCC文檔:https://gcc.gnu.org/onlinedocs/cpp/Operator-Precedence-Problems.html#Operator-Precedence-Problems

2.宏菜鳥起飛手冊:https://blog.csdn.net/hopedark/article/details/20699723

3.京東宏分享:https://mp.weixin.qq.com/s/qTFLZFL2IAz1ScrV1u313Q

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瞬项,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子何荚,更是在濱河造成了極大的恐慌囱淋,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件餐塘,死亡現(xiàn)場離奇詭異妥衣,居然都是意外死亡,警方通過查閱死者的電腦和手機戒傻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門税手,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人需纳,你說我怎么就攤上這事芦倒。” “怎么了不翩?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵熙暴,是天一觀的道長。 經(jīng)常有香客問我慌盯,道長周霉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任亚皂,我火速辦了婚禮俱箱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘灭必。我一直安慰自己狞谱,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布禁漓。 她就那樣靜靜地躺著跟衅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪播歼。 梳的紋絲不亂的頭發(fā)上伶跷,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天,我揣著相機與錄音,去河邊找鬼叭莫。 笑死蹈集,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的雇初。 我是一名探鬼主播拢肆,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼靖诗!你這毒婦竟也來了郭怪?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤刊橘,失蹤者是張志新(化名)和其女友劉穎移盆,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體伤为,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡咒循,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了绞愚。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叙甸。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖位衩,靈堂內(nèi)的尸體忽然破棺而出裆蒸,到底是詐尸還是另有隱情,我是刑警寧澤糖驴,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布僚祷,位于F島的核電站,受9級特大地震影響贮缕,放射性物質(zhì)發(fā)生泄漏辙谜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一感昼、第九天 我趴在偏房一處隱蔽的房頂上張望装哆。 院中可真熱鬧,春花似錦定嗓、人聲如沸蜕琴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽凌简。三九已至,卻和暖如春恃逻,著一層夾襖步出監(jiān)牢的瞬間雏搂,已是汗流浹背藕施。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留畔派,地道東北人铅碍。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓润绵,卻偏偏與公主長得像线椰,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子尘盼,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,490評論 2 348

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

  • http://www.open-open.com/lib/view/open1390651437117.html ...
    Xtuphe閱讀 1,255評論 0 10
  • 宏定義在C系開發(fā)中可以說占有舉足輕重的作用憨愉。底層框架自不必說,為了編譯優(yōu)化和方便卿捎,以及跨平臺能力配紫,宏被大量使用,可...
    你好自己閱讀 1,054評論 0 5
  • /**獲取屏幕寬度與高度 導(dǎo)航午阵,tabbar高度*/ #define SCREEN_WIDTH [UIScree...
    MUYO_echo閱讀 684評論 0 3
  • 喜歡讀一些開源項目源碼的人躺孝,總是會發(fā)現(xiàn),大神的代碼中總是有那么一些簡短而高效的宏定義底桂,點擊進去一看植袍,發(fā)現(xiàn)晦澀難懂,...
    我是強強閱讀 288評論 0 0
  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時...
    歐辰_OSR閱讀 29,336評論 8 265