摘要:并且在我們日常的代碼學習中,我們會碰到過很多很多的宏定義。如果宏定義中帶有參數,而代碼中出現同樣標識時沒有參數,不視為宏。具體的解析見源碼學習內存管理筆記。
grape
全部視頻:https://segmentfault.com/a/11...
原視頻地址:http://replay.xesv5.com/ll/24...
引入我們知道宏定義的優點有方便程序的修改,提高程序運行效率等等。并且在我們日常的代碼學習中,我們會碰到過很多很多的宏定義。針對這些宏定義,我們通常都是秉承著“宏即是替換”的“法則”來進行分析。然而,對于一些簡單的宏定義來說,我們直接進行替換即可完美的解決問題,但是針對于一些復雜的宏定義來說,我們會發現,替換也是有些門道的。那么,我們今天就來探索一下宏定義的神奇吧。
宏的基礎知識 一、宏替換基礎知識:#define 宏名 字符串
#define 宏名(形參列表) 字符串
允許宏帶有參數,在宏定義中的參數稱為形式參數,在宏調用中的參數稱為實際參數
每次宏展開的結果會被重復掃描,知道沒有任何可展開的宏為止。
每展開一個宏,都會記住這次展開,在這個宏展開的結果及其后續展開中,不再對相同的宏做展開。
帶參數的宏,先對參數做展開,除非定義體中包含#或##
a. "#"表示將后續標識轉化為字符串。 b. "##"標識將兩個標識連接成一個標識符。 c. 注意參數展開的結果中即使有逗號,也不要視為參數的分隔符。
如果宏定義中帶有參數,而代碼中出現同樣標識時沒有參數,不視為宏。
示例
首先我們看一個最簡單的替換:
#include#define foo(bar) bar int main() { printf("%s ",foo("grape")); return 0; }
結果相信大家一眼就可以看出來,是的輸出“grape”,如圖所示:
對應于注意事項中的的一項,展開所有的宏,我們來看這樣一個代碼:
#include#define foo(bar) bar1 #define bar1 "hello" int main() { printf("%s ",foo("grape")); return 0; }
結果是什么呢?
好的,結果和大家想的一樣,就是hello,如圖所示:
繼續,對于第二個注意事項,首先我們分析一下這個事項是為什么。相信大家都知道遞歸,倘若一個遞歸沒有結束條件會怎么樣,結果肯定是無限的執行下去,如果,我們的宏定義也會出現這個情況,那。。。讀者自行腦補吧。基于這個場景我們來看看這第二條規則,我們看一下這種情況,當然為了簡單,這段代碼是不可執行的:
#define foo foo bar
我們來看這個foo的定義,如果我們不知道這項規則,這段代碼被我們來解析,按照替換來講,我們是不是會認為是"... bar bar foo ..."這樣子?然而真實的情況是這樣子的:
foo //|->foo bar //| |~ |->bar bar foo //| |-> foo bar bar foo (至此展開完畢)
所以,同一個宏定義是不可循環展開的。
對于#和##的注意,在我們的日常代碼學習中,我們很少遇見#和##,所以相信大家對此都十分陌生,現在讓我們來看看它究竟有什么作用。見代碼:
#include#define f(a,b) a##b #define g(a) #a #define h(a) g(a) int main() { printf("%s ",h(f(1,2))); //result1 printf("%s ",g(f(1,2))); //result2 return 0; }
大家可以先看一下代碼,考慮一下result1和result2會輸出什么?
結果如圖所示:
然后我們可以想一下,如果沒有#和##會輸出?
#include#define f(a,b) b #define g(a) a #define h(a) g(a) int main() { printf("%d ",f(1,2)); printf("%d ",h(f(1,2))); printf("%d ",g(f(1,2))); return 0; }
結果如圖所示:
對比兩者我們會發現#和##的作用。即帶參數的宏執行時,我們通常先對參數的宏進行展開,但是,在參數的宏中擁有#或者##的時候,會最后才進行展開。
第四點注意事項,就會很容易理解,舉個例子,聲明一個有入參的函數,如果你只去調用函數名會出現什么問題?當然,還有另外一種情況,例如:
#define _BIN_DATA_SIZE(num, size, elements, pages, x, y) size, static const uint32_t bin_data_size[] = { ZEND_MM_BINS_INFO(_BIN_DATA_SIZE, x, y) }; #define ZEND_MM_BINS_INFO(_, x, y) _( 0, 8, 512, 1, x, y) _( 1, 16, 256, 1, x, y) _( 2, 24, 170, 1, x, y) _( 3, 32, 128, 1, x, y) _( 4, 40, 102, 1, x, y) _( 5, 48, 85, 1, x, y) _( 6, 56, 73, 1, x, y) _( 7, 64, 64, 1, x, y) _( 8, 80, 51, 1, x, y) _( 9, 96, 42, 1, x, y) _(10, 112, 36, 1, x, y) _(11, 128, 32, 1, x, y) _(12, 160, 25, 1, x, y) _(13, 192, 21, 1, x, y) _(14, 224, 18, 1, x, y) _(15, 256, 16, 1, x, y) _(16, 320, 64, 5, x, y) _(17, 384, 32, 3, x, y) _(18, 448, 9, 1, x, y) _(19, 512, 8, 1, x, y) _(20, 640, 32, 5, x, y) _(21, 768, 16, 3, x, y) _(22, 896, 9, 2, x, y) _(23, 1024, 8, 2, x, y) _(24, 1280, 16, 5, x, y) _(25, 1536, 8, 3, x, y) _(26, 1792, 16, 7, x, y) _(27, 2048, 8, 4, x, y) _(28, 2560, 8, 5, x, y) _(29, 3072, 4, 3, x, y)
我們在第一次看到_BIN_DATA_SIZE只認為是一個形量傳入到函數中,沒有做宏替換,在_替換之后會被掃描到重新做替換。具體的解析見【PHP源碼學習】2019-03-11 PHP內存管理3筆記。
結尾在我們的工作或者學習中,會出現很多復雜的宏替換,只要我們認定“宏即是替換”以及記住以上注意事項,那么一切復雜宏替換都是紙老虎。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/31519.html
摘要:此文用于匯總跟隨陳雷老師及團隊的視頻,學習源碼過程中的思考整理與心得體會,此文會不斷更新視頻傳送門每日學習記錄使用錄像設備記錄每天的學習源碼學習源碼學習內存管理筆記源碼學習內存管理筆記源碼學習內存管理筆記源碼學習基本變量筆記 此文用于匯總跟隨陳雷老師及團隊的視頻,學習源碼過程中的思考、整理與心得體會,此文會不斷更新 視頻傳送門:【每日學習記錄】使用錄像設備記錄每天的學習 PHP7...
摘要:那么問題來了,為什么要把如此簡單的一個數組初始化問題復雜化這樣寫代碼真的真的不會被別人錘嗎其實源碼中還有其他相關部分我們可以看到,源碼中提供了三個類似的宏替換結構。 baiyan 全部視頻:https://segmentfault.com/a/11... 源視頻地址:http://replay.xesv5.com/ll/24... 復習 PHP內存分配流程 showImg(https:...
摘要:調用函數時,它將用戶釋放的內存塊連接到空閑鏈上。這個聯合體共占用字節。是數字,且順序遞增位置固定,如訪問是的元素,即,就直接訪問數組的第個位置即可即,這樣就不需要前面的索引數組。 baiyan 全部視頻:https://segmentfault.com/a/11... 原視頻地址:http://replay.xesv5.com/ll/24... 本筆記中部分圖片截自視頻中的片段,圖片版...
閱讀 3460·2019-08-30 13:15
閱讀 1400·2019-08-29 18:34
閱讀 822·2019-08-29 15:18
閱讀 3480·2019-08-29 11:21
閱讀 3247·2019-08-29 10:55
閱讀 3688·2019-08-26 10:36
閱讀 1869·2019-08-23 18:37
閱讀 1816·2019-08-23 16:57