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

解决 VS运行编码错误“文本后缀“”无效;未找到文本运算符或文本运算符模板“operator ““““”&&&控制台中文乱码问题 VS运行编码错误“文本后缀“”无效;未找到文本运算符或文本运算符模板“operator """"”&&&控制台中文乱码问题。 阅读详情

目录

写在前面

认识宏  # 和 ##

#的学习

##的学习

实战


写在前面

        最近依然在嵌入式遨游,以及加深对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中的库里经常用到 # 和##来封装库函数。

C/C++/中宏特殊字符的含义及用法总结(“#”、“##”、"#@"、“\”等等) 在C/C++中,宏定义是由define完成的,宏定义中有几种常见的特殊字符需要我们了解,常用的特殊字符有以下几种: #:在宏展开的时候会将#后面的参数替换成字符串; 字符串化 ##:将前后两个的单词拼接在一起; 连接化 #@:将值序列变为一个字符; 字符化 \:将两行连接起来。行连接化 我们可以使用这些特殊的字符做一些简单的测试例子: 1.# 测试 测试代码如下: #i... 阅读详情

相关推荐

遥感新手别纠结!实测ENVI 5.3、5.6、6.0三个免费版,教你混搭安装避坑

本文为遥感新手提供ENVI 5.3、5.6、6.0三个免费版的实测对比与混搭安装指南,帮助用户构建零成本高效工作流。详细解析各版本功能差异、共存安装技巧及常见问题解决方案,特别适合课程作业、毕业论文分析和遥感入门练习。

weixin_30819085的博客 473

VC++ 2019 找不到用户定义的文本运算符

严重性 代码 说明 项目 文件 行 禁止显示状态 错误(活动) E2486 找不到用户定义的文本运算符 base src\base\BaseSocket.cpp 66 解决方法: 工具=>选项=>文本编辑器=>C/C++ => 高级=>禁用波形曲线=> True ...

CyrusZhou的专栏 3万+

python-调用动态链接库dll/so的方法

使用python ctyeps CDLL来调用linux下的so动态链接库或windows下的dll动态链接库

XIAOXIANG233233的博客 3662

C++初探 2(初涉C++)

类是用户定义的一种数据类型。要定义类,需要描述它能够表示声明信息和可对数据执行那些操作。类之于对象 就像 类型之于变量。类定义:描述的是数据格式及其用法。对象:是根据数据格式规范创建的实体。打个比方,如果类就好比所有著名演员,那么对象就好比某个著名的演员。而如果用OOP术语来表示,那么C++中的类就对应于某些语言中的对象类型,而C++对象对应于对象实例或实例变量。拿cout来举例:它是一个ostream类的对象。

w_pab的博客 1413

C++版Cesium实战:从OpenGL到3DTiles的全流程开发指南

本文提供了一份C++版Cesium全流程开发指南,详细阐述了如何利用OpenGL和Qt从零构建高性能、可离线部署的三维GIS应用。内容涵盖开发环境搭建、OpenGL渲染引擎初始化、Cesium核心坐标系与场景管理移植,并重点解析了3DTiles数据的解析、异步加载与渲染优化等硬核实战技术,旨在帮助开发者实现与现有C++工业软件的深度集成。

weixin_28077113的博客 164

【LPDDR4 - 学习二】LPDDR4 介绍 ——LPDDR4 芯片引脚说明解析

本文系统解析了LPDDR4内存芯片的引脚定义与特性,重点介绍了272球POPFBGA封装的双通道架构。内容涵盖电源管理(三级供电架构与上电时序)、控制信号(差分时钟与复用命令总线)、数据接口(16位双向数据总线与选通信号)以及校准复位等核心模块。通过表格详细列明了各引脚电压范围、功能定义及工程注意事项,并附有典型封装球位分布图。全文基于JEDEC标准,为移动设备内存设计提供全面的硬件参考,特别强调电源时序控制、信号完整性及抗干扰设计等关键点。

zap15622077817的博客 2641

编程语言特性归类总结

……(学过啥语言记啥语言) 学编程语言到一定程度总会看到“高级特性”这一字眼的章节,本人学的不精,这篇当作笔记,有新学到的就更新一下O(∩_∩)O 一、编程语言特性 ## 面向过程 命名空间、作用域、程序段 程序的有效区域 c、c++、c#、php 变量、静态变量 常量、常变量 常变量const 别名、引用 同一处内存的不...

natural_Caduceus 1884

保姆级教程:用Python+OpenCV搞定Orbbec Gemini深度与彩色流对齐(附完整代码)

本文提供了一份详细的Orbbec Gemini深度与彩色流对齐教程,涵盖从环境配置到完整代码实现的每一步。通过解析深度流对齐原理,对比不同对齐模式,并提供工业级应用中的问题排查方法,帮助开发者快速掌握Orbbec Gemini相机的使用技巧。文章还包含进阶应用如点云生成与三维重建的实战代码。

weixin_29090917的博客 470

C++中的##、#符号含义

在C++中,## 和 # 是两个不同的预处理符号。这些符号都是在C++的预处理阶段使用的,用于在代码编译之前对文本进行操作。

记录值得记录的东西 5806

华为OD机考双机位C卷 - 手机App防沉迷系统(Java & Python& JS & C/C++ & GO )

华为OD机考双机位C卷 - 手机App防沉迷系统(OD上机考试双机位C卷)。提供在线OJ刷题。Java、C++、Python、GO语言、C语言、JavaScript题解,并提供完整思路讲解。

算法大师! 2062

ARM Linux工控板+C# .NET Core:倍福ADS协议轻量化工业控制(附跨平台部署代码)

某自动化设备厂的倍福PLC控制系统曾依赖传统x86工控机:单台设备需配备1台Intel i5工控机(成本约8000元),功耗30W+,且Windows系统稳定性受工业环境干扰(如电磁辐射导致蓝屏)。更棘手的是,设备需部署在产线边缘(空间狭小),x86工控机的体积(4U机架)和散热需求(风扇噪音)难以适配;而多设备部署时,高硬件成本和高功耗导致年运维成本超20万元。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 954

C语言:宏定义中#和##的使用

#被称为连接符(concatenator),用来将两个Token连接为一个Token,##符是把传递过来的参数当成字符串进行替代。这样每次divider(除数)为0的时候便会在标准错误流上输出一个提示信息。例二:Canopen协议中对象字典和相关变量的关联。

weixin_44498318的博客 1518

视觉SLAM十四讲slambook2示例代码所有依赖库的编译安装教程(VTK、OpenCV3、ceres、Sophus、g2o、Eigen、Pangolin、googletest等)

这是2021年的最后一篇博客~ 新年快乐! 0 准备工作   首先需要先安装cmake编译器: sudo apt-get install cmake   以及,将十四讲的示例代码克隆下来(十四讲的源码地址点击这里): git clone --recursive https://github.com/gaoxiang12/slambook2.git   由于里面的3rdparty文件夹内所有内容都来自于其他github仓库,所以需要加上--recursive参数,不然克隆下来的内容不完整。   如果你.

zeeq的博客 7839

C++ 常用特征-宏-宏函数-#define

文章目录1.简单类型2.宏函数   宏是编译软件特定功能的实现,在编译前执行,有许多非常有用的功能。首先介绍最常用的宏,#define, 它是C语言中的一个宏定义命令,它用来将一个标识符定义为一个字符串,该标识符被称为宏名,被定义的字符串称为替换文本。 该命令有两种格式:一种是简单的宏定义,另一种是带参数的宏定义。范例如下所示: 1.简单类型 #define <宏名> <字符串> #define PI 3.1415926 2.宏函数 #define <宏名> (<

插件开发 1916

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

vs2015下C++ 宏提示 未找到用户定义的文本运算符 解决方法

vs2015下C++ 使用带参宏提示 未找到用户定义的文本运算符录标题 原来是这样的,不影响编译,但是有个波浪线看起来就好烦~ 解决方法 工具->选项->文本编辑器->C/C+±>高级->禁用波形曲线->true 设置后 这样是不是爽多了! ...

qq_16755585的博客 1万+

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

关于C++中的# ##

文章目录使用注意先讲#再讲## 使用注意 微软的编译器,要求预处理器指令的符号必须是不是空格的行的第一个字符. #,##都是预处理器命令,所以不能随意在代码各个地方出现,比如, cout<<#test<<endl 这样是不行的,会报“预处理器命令必须作为第一个非空白空间启动” 目前一般用法是通过define来使用这两个符号 #define STR(a) #a #define CONCAT(a,b) a##b 先讲# #这个预处理命令是将一个类型或变量或函数的名字转为字符串

逐日者 2731

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

C语言中##和#在宏定义中的用法

C语言的宏定义由于其特殊性具有特别高的可玩性,本篇文章介绍在宏定义中##和#的意义和用法。

m0_61195936的博客 418

C语言宏定义中的 “#” 和 “##”

#include <stdio.h> // #(stringizing) 字符串化操作符。 // 作用:将宏定义中的传入参数名转换成用一对双引号括起来的参数名字符串。 // 其只能用于有参数传入的宏定义中,且必须置于宏定义参数名前面。 // 对空格的处理: // 1. 忽略传入参数名前后的空格; // 2. 当传入参数名的中间存在空格时,编译器会自动连接各子字符串, // 且每个子字符串中只以一个空格连接,忽略多余一个的空格。 #define EXP(x) printf(".

记录自己工作生活中遇到的问题 1873

找不到用户定义的文本运算符_Power Query — 运算符,注释

题记:“学术地学,业务地用。”不少人问我这有什么用啊,那个有什么用啊……其实这类问题都不太好回答。它和“买菜用不到微积分,学高数有什么用?”这类问题挺像的,答案大家都知道。我觉得既然微软官方给已经很完善的Excel添加了这么一套BI插件,要么是用户有这个需求,要么是微软觉得这是符合未来需求的产品,而且这个产品确实丰富了Excel的功能,也确实能够在一些地方用得上,那么沉下心来学一学并没有太大的问题...

weixin_39833270的博客 3569

C++中的#与##

内容简介#的作用##的作用注意点 #的作用 #用于将一个宏参数字符串化 // 代码一 #include <string> #include <iostream> #define test_jing(inner_str) #inner_str int main() { std::string str="sfjsljfas"; std::cout<<test_jing(str); return 0; } 可得到输出: 可见这里#只是无脑地将宏

一身骄傲小小裴 1300

c/c++ 宏定义里的#和##

其中的 VAL2STR(200) 被替换成了 ("200"),fun_call_rt(func) 中的 #func 被替换成了 "func_for_test(10)",即都被替换成了字符串,在c语言中应该称为字符数组类型。因为 NAME_JOIN(func_for_test1, _1) 只是简单的把两个短语连接为一个短语,而连接后的这个短语是否有效那就要做语法检测了,如上面执行的结果为:打印函数的地址。我们可以直接用gcc -E 预编译看看宏展开后是什么样的?2, ## -- 连接两个语句为一个语句。

tianyexing2008的博客 2771

C++ "#"的作用和用法

本系列文章由 @yhl_leo 出品,转载请注明出处。 文章链接: http://blog.youkuaiyun.com/yhl_leo/article/details/48879093 1 #和##的作用和用法 C/C++ 的宏中,#的功能是将其后面的宏参数进行字符串化操作,简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个双引号。##连接符号由两个井号组...

weixin_33978016的博客 722

c++中的#和##用法

c++中的##和##用法

要把所有那些负面的信息当做对自身行为的评价,而不是对自身价值的评判。 459
上一篇: 基于STM32的Free-RT-OS的两种时基的认识以及重写ms,us级延时
下一篇: 基于STM32结合CubeMX学习Free-RT-OS的源码之任务创建
昊月光华
博客等级 码龄6年 340粉丝 158原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值