C++宏编程技巧

news/2024/11/7 14:30:55/

下面的代码并非按照规范格式来写,仅作示范用途。

常用符号

  • ##

连接符,可将多个标识符拼接起来,组成一个完整的标识符。

//定义宏,用来打印整型变量
#define PRINT(x)	printf("%d\n", a##x)int a1 = 1;
int a2 = 2;PRINT(1);	//等同于printf("%d\n", a1),输出1
PRINT(2);	//等同于printf("%d\n", a2),输出2
  • #

添加双引号,转成字符串。

//定义宏,转成字符串
#define STR(x)	#x//等同于printf("%s\n", "Hello, world!");
printf("%s\n", STR(Hello, world!));
  • #@ 

添加单引号,转成字符。

//定义宏,将x转成字符
#define CH(x)	#@xchar a = CH(M);	//等同于char a = 'M'
printf("%c\n", a);

除了这些基本符号以外,还有一些巧妙使用技巧。

可以利用宏来完成注册类功能的实现。

高阶技巧

  • 注册类

在微软的MFC框架中,时常可以见到窗口注册类的身影。

通过API将用户自定义的类注册一下,便可以使用它们执行某些特定的功能。

这里我要介绍的是,自定义注册方法和调用类的方法,将用户自定义类注册成功后就可以通过类名来获取该类的对象,这在没有反射机制的C++中是十分有用的功能。

  • 用户可以用map容器存储['A', func]键值对,实现类与特定函数一一对应关系。
  • 规定注册类的权限,只有注册后才能执行某些操作。
  • 将类名字符串保存在数组中,使用for循环语句或if...else条件语句动态创建所需的类。

下面对注册类的一种简单使用进行举例:

//定义用来生成类、注册类的宏
//组合类名
#define CLS(x)	My##x
//创建注册类
#define CREATE_CLS(x) \
class CLS(x) : public RegCls	\
{	\
public:	\CLS(x) *Instance() 	\{	\static CLS(x) *pInstance = new CLS(x);	\if (pInstance == nullptr)	\{	\pInstance = new CLS(x);	\}	\return pInstance;	\}	\
}
//使用类名进行类注册,#x用来将类名转成字符串
#define REG(x)	\
CREATE_CLS(x)	\
g_ClsMap[#x] = CLS(x)::Instance

 其中g_ClsMap是全局变量,需要自定义。

“\”符号用来连接多行代码,表明它们属于同一个宏定义。

CLS(x)用来组合连接类名,生成标识符My##x,如CLS(Dog)会产生标识符MyDog。

下面定义方法来调用注册类:

//定义类型func,返回RegCls *类型,无参函数
typedef std::function<RegCls *()> func;
//定义全局map变量,保存类名字符串和获取单例的函数指针
std::map<string, func> g_ClsMap;//注册两个类,类名分别为MyDog和MyCat
REG(Dog);
REG(Cat);//使用"Dog"和"Cat"字符串获取类的单例对象
RegCls *pDog = g_ClsMap["Dog"]();
RegCls *pCat = g_ClsMap["Cat"]();

本人在使用宏的过程中,还总结了一个可简化代码的宏使用技巧。

相信在编程过程中,经常会遇到相似代码重复多次出现的情况,显然宏就是为这种重复工作而生的东东。

举例如下:

//fd为文件描述符,以只读模式打开a.txt文件
int fd = open("a.txt", O_RDONLY);
if (fd < 0)
{cout << "open failed\n";return -1;
}//读取fd所指的文件内容,并保存在buf中
int res = read(fd, buf, sizeof(buf));
if (res < 0)
{cout << "read failed\n";return -1;
}

上面是Linux系统中常见的打开文件并读取文件内容的操作,可发现判断返回结果的代码都是类似的,很容易联想到使用宏进行简化。其实宏定义的位置也有讲究,不仅可在文件头部定义,也可以在函数内部定义。无论在函数内部还是外部定义宏,都可以在之后使用该宏,作用域均为全局范围。

通过#define和#undef组合,可以将宏作用域限制在标签之间。

使用宏简化代码如下:

//定义宏,检查变量值
#define CHECK(x, str)	\
if (x < 0)	\
{	\cout << str << " failed\n";	\return -1;	\
}int fd = open("a.txt", O_RDONLY);
CHECK(fd, "open");int res = read(fd, buf, sizeof(buf));
CHECK(res, "read");//取消宏定义
#undef CHECK

这段代码可以放到函数内部,用时定义,用完即销。

咦!为啥代码行数反而增加了!其实不然,这里我们定义的宏只用到了两次,所以效果不佳,但当使用次数增加到3次、10次甚至更多时,宏的作用将会体现得淋漓尽致! 

本次关于宏的介绍就到此为止,如有不对之处,请多多指教!

 


http://www.ppmy.cn/news/674043.html

相关文章

获取并设置鼠标位置 C语言

转自&#xff1a;YALI_xunzhen 编译环境&#xff1a;DEV C 4.9.9.2(及以上) 所在函数库&#xff1a;windows.h 格式&#xff1a; 读取鼠标坐标 GetCursorPos(一个POINT变量地址) 设定鼠标坐标 SetCursorPos(坐标x值,坐标y值) PS:将鼠标移到(x,y) 下面是例子&#xff1a;移…

C语言中宏(macro)的特殊用法

SimpleScalar的源代码中对macro的运用可以说是炉火纯青&#xff0c;丰富的macro使得代码简介&#xff0c;逻辑清晰&#xff0c;但是也给我这些初学者们阅读代码造成了障碍&#xff0c;下面将几篇找到的相关资料贴出来&#xff0c;希望能对大家有用 C语言中的宏(Macro)是最令人…

C语言宏的主要作用

宏主要有四大类作用&#xff1a; 1.和条件编译指令配合&#xff0c;进行条件编译. 比如: 1)头文件的防止多重包含机制. 2)根据不同编译器选择不同代码段. 2.对需要变动的常量进行控制. 比如: 控制定义数组的长度. 3.对应码(比如寄存器功能码、状态码、指令的参数码、一些协议的…

c语言的 宏

一、常规宏定义 在 C 语言中&#xff0c;可以采用命令 #define 来定义宏。该命令允许把一个名称指定成任何所需的文本&#xff0c;例如一个常量值或者一条语句。在定义了宏之后&#xff0c;无论宏名称出现在源代码的何处&#xff0c;预处理器都会把它用定义时指定的文本替换掉…

C语言控制和鼠标键盘 (windows环境)

C语言控制鼠标点击以及键盘输入 使用场景主要的几个函数介绍实例键盘输入对应值 使用场景 当需要实现一些重复的点击&#xff0c;或者自动输入的情况下&#xff0c;可以使用到类似的功能&#xff0c;例如网页的自动刷新&#xff0c;QQ的自动输入&#xff0c;&#xff08;嘴炮连…

c语言中的宏的妙用

文章背景 前段时间&#xff0c;为了做一个项目中的程序&#xff0c;大致是实现SQL类似功能的索引功能&#xff0c;需要建立一张索引表&#xff0c;分析后&#xff0c;该表是在程序运行前就存在的&#xff0c;在参考优秀代码后&#xff0c;自己还是决定用宏来写这样一个功能的实…

【C语言进阶】宏

&#x1f680;write in front&#x1f680; &#x1f4dc;所属专栏&#xff1a;> c语言学习 &#x1f6f0;️博客主页&#xff1a;睿睿的博客主页 &#x1f6f0;️代码仓库&#xff1a;&#x1f389;VS2022_C语言仓库 &#x1f3a1;您的点赞、关注、收藏、评论&#xff0c;是…

Centos开放端口以及查看端口和防火墙配置命令

查看防火墙某个端口是否开放 firewall-cmd --query-port8080/tcp 开放防火墙端口 8080 firewall-cmd --add-port8080/tcp --permanent 开启端口后需执行 firewall-cmd --reload 使其生效 重新加载防火墙规则 firewall-cmd --reload 关闭防火墙端口 firewall-cmd --remove-port8…