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

11 篇文章 1 订阅

目录

写在前面

认识宏  # 和 ##

#的学习

##的学习

实战


写在前面

        最近依然在嵌入式遨游,以及加深对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"##str1



void fun1() {

	std::cout << "fun1\r\n";

}

 
int main() {
	std::cout << mytest(2) << "\r\n";
}

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

比如做标识符

#define finaltest(x)   fun##x

#define fun(x)    var##x
  



void 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中的库里经常用到 # 和##来封装库函数。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值