C语言代码的常用技巧

#和##对于大部分c语言玩得还算比较溜的朋友并不是很陌生,不过能把这两个知识点游刃有余的应用到所在代码中的每个角落,似乎并没有几个人能够做到,学的时候朗朗上口,而编码的时候却抛之脑后。
但是今天bug菌还是想重新介绍这两个“兄弟”,希望大家能够写出秀一点的代码~
1#和##基础
对于这两个语法的功能都比较简单,且都是在预处理阶段做一些工作 :
#主要是将宏参数转化为字符串
##主要是将两个标识符拼接成一个标识符
没点代码似乎并不是那么形象 : 
参考demo:
1#include  2#include  3 4//#的简单使用  5#define str(str) #str 6 7//##的简单使用 8#define  cmb(a,b) a##b 910int main(int argc, char *argv[]) {1112    int cmb(uart,1) = 5;13    int cmb(uart,2) = 10;1415    printf(#的简单使用:);16    printf(%s,str(3.1415));17    printf(%s,str(abcd));1819    printf(##的简单使用:);20    printf(%d,uart1);    21    printf(%d,uart2);2223    return 0;24}  
输出结果:
从结果上看来似乎#仅仅只是代替了字符串的双引号,而##却实现了标识符的拼接,这样就为编码标识符的处理上能够带来更多的可玩性。 那么,下面bug菌跟大家具体展示一下他们的常用技巧:  
2#的玩法
1、标识符的“字符串变量
“#”一般结合打印语句组合成一个宏定义,可以方便的打印相关信息,下面给个简单的实例就明白了。
1#include  2#include  3 4//#打印调试  5#define debuglogexpr(expr)     printf(%s : %d,#expr, expr);   6 7//私有参数访问  8int sfucntion(void) 9{10    static int var = 10;11    return var;12} 1314int main(int argc, char *argv[]) {1516    int debugvar = 50;1718    debuglogexpr(debugvar);     //直接打印变量名和变量 19    debuglogexpr(100/5);        //打印表达式及结果 20    debuglogexpr(sfucntion());  //打印相关函数名及结果 2122    return 1;23}  
输出结果:
这样的话就不需要总是采用双引号来单独书写,同时你还可以继续扩展构造更加灵活的宏。
2、结合##进行字符串拼接打印
前面介绍了##进行标识符的拼接,那么实现拼接标识符转化为字符串看来很简单吧,于是你会编写了如下代码:
1#include  2#include  3 4//#的简单使用  5#define str(str) #str 6 7//##的简单使用 8#define  cmb(a,b) a##b 910int main(int argc, char *argv[]) {1112    int cmb(uart,1) = 5;1314    printf(%s,str(cmb(uart,1)));1516    return 0;17}  暗自欢喜的编译着,然而却得到了如下结果:
得到的并不是拼接以后你想要的uart1,难道不能这么玩?当然不是,不然也不会在这里拿出来说 。 首先要知道原因 : 进行宏定义嵌套的情况,#或者##仅在当前宏有效,嵌套宏中不会再次展开,既然当前宏无法展开,那么我只能再加一级宏定义作为转换宏进行展开,看能不能解决该问题: 1 #include  2#include  3 4//#的简单使用  5#define str(str) #str 6 7//##的简单使用 8#define  cmb(a,b) a##b 910#define str_con(str) str(str)  //转换宏 1112int main(int argc, char *argv[]) {1314    int cmb(uart,1) = 5;1516    printf(%s,str_con(cmb(uart,1)));1718    return 0;19}  此时输出的结果符合我们的预期:
首先进行第一层转换宏替换处理掉##拼接符得到str(uart1),然后进行字符串转换符的处理为uart1字符串打印输出,当然以后你会遇到一些复杂的,不过要诀就是宏替换只会处理当前的#或者##,否则就需要增加转换宏提前进行宏替换展开。 所以采用##拼接出来的标识符想要打印输出的话,使用#进行转换是最直接、方便的。  
3##的玩法
##拼接符的玩法有点多,甚至有些还比较绕,当然如果你游刃有余的话,这对于重构代码是一把“ 利器 ”。
1、在结构体定义中的妙用
下面是bug菌经常在项目代码中用到的##结构体定义法,也是非常多开源代码中惯用的做法,相比常规的结构体定义法,确实省去很多重复的代码。 比如下面的参考代码 : 
1#include  2#include  3 4#define df_struct(name) typedef struct tag##name name; 5                         struct tag##name 6 7df_struct(devmanage) 8{ 9    int index;   //索引 10    int access;  //权限11                  //...  12};1314int main(int argc, char *argv[]) {1516   devmanage stdevmanage;1718   stdevmanage.index  = 1;19   stdevmanage.access = 666;2021    printf(dev index :%d,stdevmanage.index );22    printf(dev access:%d,stdevmanage.access );2324    return 1;25}  2、统一宏替换


USB Type-C直角型线缆的6个优势
电热鼓风干燥箱是如何实现温度控制的
全球存储器产业究竟难在哪里?
移动互联网下的支付方式有了怎样的改变
关于大功率高频变压器的设计
C语言代码的常用技巧
电子产品在销售之前都需要电磁兼容性EMC认证
基于LabVIEW专业版开发环境实现便携式智能型温室的搭建
安森美智能LED街灯与楼宇照明保护方案
美国高中生为逃课策划八次DDoS攻击,并导致地区网络崩溃
360公司表示其手机业务并非完全暂停只是放缓
西门子 S7-300 PLC经典问题及解答
2019年全球路由器市场份额报告公布,华为排名第一
Facebook在F8上公布了一项名为3D照片的新功能
SK海力士2023年HBM3营收增长5倍,AI三大件进一步拉动市场复苏
共享时代 共享电瓶的到来
焊接夹渣产生的原因_焊接夹渣的预控措施
瑞萨电子开发出可使车载信息终端及智能手机等实现高画质的函数库
浅谈半导体芯片封装的四个目的
AllSeen 联盟开源社区不断发展壮大:AllJoyn用户组计划超过600名成员