当前位置: 首页 > 后端技术 > PHP

【PHP7源码学习】2019-03-26宏定义笔记

时间:2023-03-30 02:27:27 PHP

葡萄所有视频:https://segmentfault.com/a/11...原视频地址:http://replay.xesv5.com/ll/24...简介我们知道,宏定义的优点是方便程序修改,提高程序运行效率等。而在我们日常的代码学习中,会遇到很多很多的宏定义。对于这些宏定义,我们通常遵循“宏即置换”的“规律”进行分析。但是,对于一些简单的宏定义,我们直接替换就可以完美解决问题,但是对于一些复杂的宏定义,我们会发现替换也有些取巧。那么,让我们今天来探索一下宏定义的魔力。宏的基础知识1.宏替换的基础知识:#define宏名字符串#define宏名(形式参数列表)字符串允许宏有参数。宏定义中的参数称为形参,宏调用中的参数称为实参。2、C宏展开的几个注意事项:每次宏展开的结果都会被反复扫描,直到没有可以展开的宏为止。每次展开宏时,都会记住这次展开,在本次宏展开及其后续展开的结果中不会再展开同一个宏。对于带参数的宏,首先展开参数,除非定义体中包含#或##a。'#'表示将后面的标识符转换成字符串。b.'##'标记将两个标记连接成一个标识符。C。注意,即使参数扩展的结果中有逗号,也不应将其视为参数分隔符。如果宏定义中有参数,但代码中出现相同标记时却没有参数,则不认为是宏。示例首先让我们看一下最简单的替换:#include#definefoo(bar)barintmain(){printf("%s\n",foo("grape"));return0;}结果相信大家一眼就看出来了,没错,就是输出“葡萄”,如图:对应其中一个注意事项,展开所有的宏,我们来看这样一段代码:#include#definefoo(bar)bar1#definebar1"hello"intmain(){printf("%s\n",foo("葡萄"));return0;}结果是什么?好了,结果和大家想的一样,是你好,如图:继续,对于第二个笔记,首先我们来分析一下这个项目的原因。我相信每个人都知道递归。如果递归没有结束条件会发生什么,结果一定是无限执行。如果这发生在我们的宏定义中,那么。..读者自行判断。基于这个场景,我们来看第二条规则。我们来看看这个情况。当然,为了简单起见,这段代码是不可执行的:#definefoofoobar让我们看看这个foo的定义。如果我们不知道这个规则,这段代码被我们解析了。在替换方面,我们会不会认为是“...barbarfoo...”?然而真实情况是这样的:foo//|->foobar//||~|->barbarfoo//||->foobarbarfoo(展开至今)所以,同样的宏定义是不可递归展开的。对于#和##的注意,在我们日常的代码学习中,我们很少会遇到#和##,所以相信大家对它还是很陌生的,下面就让我们看看它是干什么的。参见代码:#include#definef(a,b)a##b#defineg(a)#a#defineh(a)g(a)intmain(){printf("%s\n",h(f(1,2)));//结果1printf("%s\n",g(f(1,2)));//result2return0;}大家可以先看看代码,考虑一下result1和result2会输出什么?结果如图:那我们可以想一下,如果没有#和##会输出吗?#include#definef(a,b)b#defineg(a)a#defineh(a)g(a)intmain(){printf("%d\n",f(1,2));printf("%d\n",h(f(1,2)));printf("%d\n",g(f(1,2)));return0;}Result如图:对比两者,我们会发现#和##的作用。即执行带参数的宏时,我们通常先展开参数的宏,但是当参数的宏中有#或##时,最后展开。第四个音符很容易理解。比如声明一个带入参的函数,如果只调用函数名会怎么样?当然还有另一种情况,比如:#define_BIN_DATA_SIZE(num,size,elements,pages,x,y)size,staticconstuint32_tbin_data_size[]={ZEND_MM_BINS_INFO(_BIN_DATA_SIZE,x,y)};#defineZEND_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时,我们只是把它当成一个形状量传入函数,并没有进行宏替换。_replace后,会扫描到re-replacement具体分析见【PHP源码学习】2019-03-11PHP内存管理3笔记。最后,在我们的工作或者学习中,会有很多复杂的宏替换。只要我们相信“宏就是替换”,记住上面的注意事项,那么一切复杂的宏替换都是纸老虎。