文大家好,我是虫菌!#和##对于大部分对C语言比较熟练的朋友来说,并不是很陌生,但是似乎很少有人能够将这两个知识点应用到代码的各个角落,学习的时候朗朗上口,编码的时候忘记了。不过今天BugBacteria还是要重新介绍一下这两位“兄弟”,希望大家能写出“花哨”的代码~1.在处理阶段做一些工作:#主要是将宏参数转换成字符串##主要是将两个标识符拼接成一个标识符没有点代码好像不太形象:参考demo:1#include2#includeh>34//#简单使用5#defineSTR(str)#str67//##简单使用8#defineCMB(a,b)a##b910intmain(intargc,char*argv[]){1112intCMB(uart,1)=5;13intCMB(uart,2)=10;1415printf("简单使用#:\r\n");16printf("%s\r\n",STR(3.1415));17printf("%s\r\n",STR(abcd));1819printf("##的简单使用:\r\n");20printf("%d\r\n",uart1);21printf("%d\r\n",uart2);2223return0;24}输出结果:从结果来看,#似乎只是替换了字符串的双引号,而##实现了标识符的拼接,这样对于编码标识符的处理可以带来更多的可玩性。那么,下面的虫菌就为大家详细展示一下它们的常用技巧:2.#的玩法(1)标识符的“字符串变量”“#”一般与打印语句组合成宏定义,可以方便打印相关信息,下面举个简单的例子来理解。1#include2#include34//#打印调试5#defineDebugLogExpr(Expr)printf("%s:%d\r\n",#Expr,Expr);67//私有参数访问8intsFucntion(void)9{10staticintvar=10;11returnvar;12}1314intmain(intargc,char*argv[]){1516intDebugVar=50;1718DebugLogExpr(DebugVar);//直接打印变量名和变量19DebugLogExpr(100)/5);//打印表达式和结果20DebugLogExpr(sFucntion());//打印相关函数名和结果2122return1;23}输出结果:这样就不用一直用双引号单独写了,你可以继续Expansion构造更灵活的宏。(2)结合##进行字符串拼接和打印上面介绍了##用于拼接标识符,将拼接标识符转换成字符串似乎很简单,所以会写如下代码:1#include2#include34//#简单使用5#defineSTR(str)#str67//##简单使用8#defineCMB(a,b)a##b910intmain(intargc,char*argv[]){1112intCMB(uart,1)=5;1314printf("%s\r\n",STR(CMB(uart,1)));1516return0;17}偷偷编译,却得到如下结果:拼接后得到的不是你想要的uart1,这样玩不行吗?当然不是,不然我也不会在这里说了。首先要知道原因:在嵌套宏定义的情况下,#或##只在当前宏中有效,不会在嵌套宏中再次展开。既然不能展开当前宏,那我只能再加一层宏定义作为转换展开宏看看能不能解决问题:1#include2#include34//#简单使用5#defineSTR(str)#str67//##简单使用8#defineCMB(a,b)a##b910#defineSTR_CON(str)STR(str)//转换宏1112intmain(intargc,char*argv[]){1314intCMB(uart,1)=5;1516printf("%s\r\n",STR_CON(CMB(uart,1)));1718return0;19}此时的输出结果符合我们的预期:首先进行第一层转换宏替换去掉##拼接字符得到str(uart1),然后对字符串转换字符的处理就是uart1字符串打印输出。当然以后会遇到一些复杂的问题,但关键是宏替换只会处理当前的#或##,否则需要提前添加转换宏进行宏替换和扩展。.因此,如果要打印出##拼接的标识符,使用#进行转换是最直接方便的。3.##的游戏##拼接角色的玩法有很多种,有的更绕口。当然,如果你用得舒心,这是重构代码的“利器”。(1)结构体定义的妙用以下是bug菌在项目代码中经常使用的##结构体定义方式,也是很多开源代码中的常见做法。与传统的结构定义方法相比,它确实是经济的。转到很多重复的代码。例如下面的参考代码:1#include2#include34#defineDF_STRUCT(name)typedefstructtag##namename;\5structtag##name67DF_STRUCT(DevManage)8{9intindex;//index10int访问;//权限11//...12};1314intmain(intargc,char*argv[]){1516DevManagestDevManage;1718stDevManage.index=1;19stDevManage.Access=666;2021printf("DevIndex:%d\n",stDevManage.index);22printf("DevAccess:%d\n",stDevManage.Access);2324return1;25}(2)统一的宏替换拼接标识符意味着符号的粒度更高,碎片化符号的有效管理,可以使符号更多才多艺和灵活。其实这个思路和我们的代码模块是一样的。先来体验一下两层拼接:1#include2#include34//如果这是stm32库中的宏5#defineGPIO_Pin_0((int)0x0001)/*!