目录

写在前面

认识宏  # 和 ##

#的学习

##的学习

实战


写在前面

最近依然在嵌入式遨游,以及加深对free rt os 源码以及内核的理解。以及为了解决学习工作中分布式设备的命名问题。于是就想到了  #和##这两个宏。

认识宏  # 和 ##

既然都是宏,则它们在编译的第一个阶段也就是预编译阶段被替换掉,在程序的运行过程中不存在宏。

#的学习

试想我能不能在字符串中插入变量。答案就是#。它必须放在变量前,把变量字符串化。 #A 为 "A" (A必须在编译器被确定)

作用:

  • 字符串化,在字符串中插入参数值。
  • 连接作用

#define  DEV(X)   "DEV"X             // 于是DEV(1)   就为 "DEV1"

#define dev(x)  "dev("#x")"
#define mytest(x)  "test"#x
int main() {std::cout << dev(1) << "\r\n";std::cout << mytest(21) << "\r\n";}

结果

从结果看到确实能把参数字符串化并它们拼接在一起。

但是:#的单独使用并不能连接字符串。 正如上面所提到到,他必须要放在参数前,可以通过以下方式连接两个字符串.

#define test3(x)  "hello"#x"world"     

测试:std::cout<<test()<<"\r\n"; // x被空字符串替代输出为  helloworld

而当我想用这样的方式两个两个以上的字符串的宏时却发现不行。

比如这样的形式会报错(编译不通过,因为不认识 xstr2)

#define str1 "hello"
#define str2 "world"
#define test3(x)  str1#xstr2

这时就需要 宏 ##字符串出马了!

str1#x##str2    //把三个字符串拼接

#define str1 "hello"
#define str2 "world"
#define test3(x)  str1#x##str2
int main() {std::cout << test3() << "\r\n";}

试想既然是在预编译就会被替换,哪#能不能变函数呢?

比如

void fun1() {std::cout << "fun1\r\n";}#define finaltest(X)    fun#X()int main() {finaltest(1);}

结果报错,原因是fun是未定义的标识符,而把宏改成"fun"#x"()",则更加不行,这从根本上就是字符串啊。。。至于我为什么要这么做,这看上有些笨拙,当这正是认识的过程,当然,这也为我引入后面的 宏 “##”

##的学习

有了上面的认识,就知道 宏 ##可以连接任意的字符串,可以连接任意字符串的宏。同时它可以做标识符、

作用

  • 连接任意字符串
  • 做标识符。(花里胡哨用)

比如连接字符串

#define str1  "hhhhhh"
#define mytest(x)    "hello"#x##"world"##"my name is yzh"##str1void fun1() {std::cout << "fun1\r\n";}int main() {std::cout << mytest(2) << "\r\n";
}

这个VS上提升找不到用户定义的文本运算符,当依然能够编译成功并运行。

比如做标识符

#define finaltest(x)   fun##x#define fun(x)    var##xvoid fun1() {std::cout << "fan1\r\n";
}int main() {int fun(1) = 21;var1 = 999;std::cout << fun(1) << "\r\n";finaltest(1)();
}

运行

实战

在不同的网络下,不同的设备连接不同的网络,订阅各自由自己的名字组成的主题,发布由自己的名字组成的主题。

比如 ,设备名是ESP1  ,订阅 dev/set/ESP1 ,发布 dev/date/ESP1 ,发布 callback/ESP1 。同时,能方便更改所连接的WIFI,所连接的服务器地址(ip)以及连接服务器所对应的端口。

WIFI账号和密码,服务器地址,端口这些用简单的宏定义就行了。

比如

#define WIFINAME   "WIFI"

关键在于要把它们组成AT指令的报文,所以就有固 定的格式,对命令的每个部分都有明确的要求。这时候  宏 # 和  ##就派上用场了。


#define  WIFINAME   "rookie"      //WIFI用户名
#define   WIFIPWD    "yy061457"    //WIFI密码
#define   MQTTNAME   "admin"       //服务器用户名
#define   MQTTPWD    "061457"        //服务器密码
#define   MQTTPORT   "1883"           //服务器端口
#define   MQTTURL    "192.168.1.13"    //服务器地址#define  DEVNAME(X)    "ESP"#X   //设备名
#define REALNAME DEVNAME(1)     //真正要用到的设备名
#define  PUBTOPICALL  "callback/"##REALNAME    //发布主题
#define  SUBTOPICCMD  "dev/set/"##REALNAME      //订阅主题
#define PUBTOPICDATE   "dev/date/"##REALNAME     //订阅主题名extern __IO u8 mqttstate;//订阅主题格式
#define SUBTOPIC   "AT+MQTTSUB=0,\"%s\",0\r\n"//发布对应主题对应信息格式
#define PUBTOPIC  "AT+MQTTPUB=0,\"%s\",\"%s\",0,0\r\n"//连接对应WIFI  账号 密码
#define CONNECTWIFI  "AT+CWJAP=\
\""##WIFINAME##"\",\
\""##WIFIPWD##"\"\r\n"//清除MQTT连接信息#define  CLEANMQTTINFO "AT+MQTTCLEAN=0\r\n"//连接EMQX服务器的本地登录账号和密码#define LOGINMQTT "AT+MQTTUSERCFG=0,1,\""##REALNAME##"\",\""##MQTTNAME##"\",\
\""##MQTTPWD##"\",\
0,0,\"\"\r\n\
"//连接本地EMQX 下的mqtt服务器地址 设置断开自动重连
#define  CONNECTMQTT "AT+MQTTCONN=0,\""##MQTTURL##"\","##MQTTPORT##",1\r\n"

另外,在free rt os ,以及stm32中的库里经常用到 # 和##来封装库函数。

C/C++中#和##的宏以及进行“花里胡哨“的命名及其应用相关推荐

  1. 编写一个头文件,头文件中定义一个宏cube(x)用于求一个数的平方

    <程序设计基础实训指导教程-c语言> ISBN 978-7-03-032846-5 p145 7.1.2 上级实训内容 [实现内容17]编写一个头文件,头文件中定义一个宏cube(x)用于 ...

  2. C++头文件中预编译宏的目的

    C++头文件中预编译宏的目的 eg: #ifndef _FACTORY_H_ #define _FACTORY_H_ ...... #endif //~_FACTORY_H_ 防止头文件被重复包含,导 ...

  3. VC中的TRACE宏:

    VC中的TRACE宏: TRACE宏对于VC下程序调试来说是很有用的东西,有着类似printf的功能:该宏仅仅在程序的DEBUG版本中出现,当RELEASE的时候该宏就完全消失了,从而帮助你调式也在R ...

  4. 为什么VS(visual studio)中会建议宏 #define 转换为constexpr?

    如图: 原因: 宏是由预处理器而非编译器解析的,比如不能用命名空间,所以使用后必须解除 以及宏很容易带来各式各样的错误,最简单如括号上的错误,还有宏会导致debug困难等等 参考文章:为什么VS中会建 ...

  5. 怎样在设计中添加FIFO宏模块

    quartus软件内置了很多我们经常用到的电路模块,统称为宏模块,在做EDA设计的时候,我们可以直接调用他们来简化设计过程.不要小看了宏模块,如果利用得当,可以省去你一多半的设计时间呢.这里以FIFO ...

  6. python展开 c函数中的宏预处理_C中的预处理宏

    C中的预处理宏 宏定义就属于预处理命令的一种.那么,什么是宏呢? 宏:c语言标准允许在程序中用一个标识符来表示一个字符串.标识符就是宏名. 宏替换:宏替换就是宏定义.在编译预处理中,将程序中所有的宏名 ...

  7. Linux kernel中常见的宏整理

    0x00 宏的基本知识 // object-like #define 宏名 替换列表 换行符 //function-like #define 宏名 ([标识符列表]) 替换列表 换行符 替换列表和标识 ...

  8. C语言中预定义宏的应用

    __LINE__                       在源代码中插入当前源代码行号         __FILE__                       在源代码中插入当前源代码文件名 ...

  9. c语言宏定义比较三个数大小,C语言中两个宏进行大小对比,其中一个没有定义,这种行为如何定义。...

    1.C语言中两个宏进行大小对比,其中一个没有定义,这种行为如何定义呢? 在学习U-boot的过程中遇到这么一个定义: # if (CONFIG_ENV_ADDR >= CONFIG_SYS_MO ...

最新文章

  1. html在页面上div绝对定位,html – 中心浮动div在绝对定位div内
  2. 将线程pid转成16进制_如何使用jstack分析线程状态
  3. 多态实现机制:静态分派和动态分派
  4. 用python画xy散点图-使用python绘制散点图并标示密度
  5. kafka入门:简介、使用场景、设计原理、主要配置及集群搭建--转载
  6. XMLHttpRequest 对象
  7. WebGIS中利用AGS JS+eCharts实现一些数据展示的探索
  8. JAVA学习-----容器和数据结构
  9. IT忍者神龟之Java动态代理与CGLib代理
  10. ubuntu安装openpose
  11. 工业相机中的全局快门与卷帘快门
  12. c语言学习笔记(7)单引号,双引号和逻辑符号的用法
  13. Kienct与Arduino学习笔记(1) 基础知识之Arduino’Kinect‘Processing
  14. 香港希玛眼科集团第二届眼科精准医疗国际会议在京启幕
  15. Linux下的Cadence软件的spice和Verliog步骤(这是最最最为简单的超详细!!!!)
  16. 计算机网络实验(三个部分--验证性、Wireshark、CPT)
  17. 【Web技术】1431- 总结前端主题切换的思考和现代前端样式的解决方案落地
  18. 建设网站:购买域名和主机的原则你知道吗?
  19. CrystalDiskInfo硬盘检测工具 标准版及萌妹版
  20. java实现数据结构基数排序_数据结构与算法——基数排序简单Java实现

热门文章

  1. projece修改工期_project里工期如何更改为自然日
  2. GPS定位系统(二)——Android端
  3. 淘晶驰芯片AIHMI简介
  4. 小而美的城市,比鸭脖更诱人
  5. 滴滴裁员20%,有员工拿了N+1赔偿,转身去新公司报到,还涨薪30%
  6. Unity Shader之uv旋转
  7. android横屏分辨率,android适配不同分辨率hdpi、mdpi、ldpi横屏竖屏
  8. 最新目标跟踪评估指标汇总
  9. vue实现echarts词云图业务【详细配置版】
  10. 微软服务器无法删除不了,[图]Edge无法卸载 引发诸多用户强烈不满