C/C++中#和##的宏以及进行“花里胡哨“的命名及其应用
目录
写在前面
认识宏 # 和 ##
#的学习
##的学习
实战
写在前面
最近依然在嵌入式遨游,以及加深对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++中#和##的宏以及进行“花里胡哨“的命名及其应用相关推荐
- 编写一个头文件,头文件中定义一个宏cube(x)用于求一个数的平方
<程序设计基础实训指导教程-c语言> ISBN 978-7-03-032846-5 p145 7.1.2 上级实训内容 [实现内容17]编写一个头文件,头文件中定义一个宏cube(x)用于 ...
- C++头文件中预编译宏的目的
C++头文件中预编译宏的目的 eg: #ifndef _FACTORY_H_ #define _FACTORY_H_ ...... #endif //~_FACTORY_H_ 防止头文件被重复包含,导 ...
- VC中的TRACE宏:
VC中的TRACE宏: TRACE宏对于VC下程序调试来说是很有用的东西,有着类似printf的功能:该宏仅仅在程序的DEBUG版本中出现,当RELEASE的时候该宏就完全消失了,从而帮助你调式也在R ...
- 为什么VS(visual studio)中会建议宏 #define 转换为constexpr?
如图: 原因: 宏是由预处理器而非编译器解析的,比如不能用命名空间,所以使用后必须解除 以及宏很容易带来各式各样的错误,最简单如括号上的错误,还有宏会导致debug困难等等 参考文章:为什么VS中会建 ...
- 怎样在设计中添加FIFO宏模块
quartus软件内置了很多我们经常用到的电路模块,统称为宏模块,在做EDA设计的时候,我们可以直接调用他们来简化设计过程.不要小看了宏模块,如果利用得当,可以省去你一多半的设计时间呢.这里以FIFO ...
- python展开 c函数中的宏预处理_C中的预处理宏
C中的预处理宏 宏定义就属于预处理命令的一种.那么,什么是宏呢? 宏:c语言标准允许在程序中用一个标识符来表示一个字符串.标识符就是宏名. 宏替换:宏替换就是宏定义.在编译预处理中,将程序中所有的宏名 ...
- Linux kernel中常见的宏整理
0x00 宏的基本知识 // object-like #define 宏名 替换列表 换行符 //function-like #define 宏名 ([标识符列表]) 替换列表 换行符 替换列表和标识 ...
- C语言中预定义宏的应用
__LINE__ 在源代码中插入当前源代码行号 __FILE__ 在源代码中插入当前源代码文件名 ...
- c语言宏定义比较三个数大小,C语言中两个宏进行大小对比,其中一个没有定义,这种行为如何定义。...
1.C语言中两个宏进行大小对比,其中一个没有定义,这种行为如何定义呢? 在学习U-boot的过程中遇到这么一个定义: # if (CONFIG_ENV_ADDR >= CONFIG_SYS_MO ...
最新文章
- html在页面上div绝对定位,html – 中心浮动div在绝对定位div内
- 将线程pid转成16进制_如何使用jstack分析线程状态
- 多态实现机制:静态分派和动态分派
- 用python画xy散点图-使用python绘制散点图并标示密度
- kafka入门:简介、使用场景、设计原理、主要配置及集群搭建--转载
- XMLHttpRequest 对象
- WebGIS中利用AGS JS+eCharts实现一些数据展示的探索
- JAVA学习-----容器和数据结构
- IT忍者神龟之Java动态代理与CGLib代理
- ubuntu安装openpose
- 工业相机中的全局快门与卷帘快门
- c语言学习笔记(7)单引号,双引号和逻辑符号的用法
- Kienct与Arduino学习笔记(1) 基础知识之Arduino’Kinect‘Processing
- 香港希玛眼科集团第二届眼科精准医疗国际会议在京启幕
- Linux下的Cadence软件的spice和Verliog步骤(这是最最最为简单的超详细!!!!)
- 计算机网络实验(三个部分--验证性、Wireshark、CPT)
- 【Web技术】1431- 总结前端主题切换的思考和现代前端样式的解决方案落地
- 建设网站:购买域名和主机的原则你知道吗?
- CrystalDiskInfo硬盘检测工具 标准版及萌妹版
- java实现数据结构基数排序_数据结构与算法——基数排序简单Java实现
热门文章
- projece修改工期_project里工期如何更改为自然日
- GPS定位系统(二)——Android端
- 淘晶驰芯片AIHMI简介
- 小而美的城市,比鸭脖更诱人
- 滴滴裁员20%,有员工拿了N+1赔偿,转身去新公司报到,还涨薪30%
- Unity Shader之uv旋转
- android横屏分辨率,android适配不同分辨率hdpi、mdpi、ldpi横屏竖屏
- 最新目标跟踪评估指标汇总
- vue实现echarts词云图业务【详细配置版】
- 微软服务器无法删除不了,[图]Edge无法卸载 引发诸多用户强烈不满