C/C++宏定义和宏函数

news2024/9/25 11:13:55

1.概述

C/C++ 的宏定义和宏函数非常的有用,由于最近看Android 的jni代码时老是会看见如下图所示的宏定义:
在这里插入图片描述定义完后使用的时候直接如下使用就行了:

JMI_DECLARE_CLASS(Context,android.content);

这样就能很简洁的将一些逻辑重复的代码管理起来了,这样修改的时候也只需要修改宏定义的部分即可。上面的这种方式就是宏函数的使用方式,宏定义其实就是C/C++中使用#define 来定义的语句,如下所示:

#define PI 3.14 // 宏替换
#define MAX(a,b) ((a)>(b)?(a):(b))// 宏函数

如上面所示,宏定义分为宏替换和宏函数,本文将会介绍这两类的区别以及如何使用。

2.宏替换

我们都知道,在C语言中,#号开头的都是预处理指令,我们宏替换就是使用#define 数值或者算式来定义,需要注意的是宏替换就是单纯的替换,直接替换。我们可以通过一个例子来介绍宏替换:

假设我们需要定义一个CONST的常量,这个常量是的值是:1+2,代码如下所示:

#include<iostream>
#define CONST 1+2

using namespace std;

int main() {
	int res = 3 * CONST;
	cout << "the result is: " << res << endl;
}

很多读者可能会认为这里的结果是9,但是运行的结果却是5:
在这里插入图片描述
为啥会出现这种情况呢,这就是我们说的宏替换,宏替换只是单纯的替换,不会有运算的功能,这里的CONST后面的1+2会被直接替换到我们的表达式:int res = 3*CONST;中,替换后的样子应该是:int res = 3*1+2;根据算术运算的优先级,所以结果就为5,如果要想按照我们想要让结果为9时,需要在宏定义后面的表达式加括号,保持优先级,如:#define CONST (1+2) 如果想要正确的使用宏替换,我们一定要注意理解宏替换的本质。就是就是单纯的替换。
注意:宏替换后的语法需要满足C/C++的语法,替换之后的语句,不能违背C/C++的语法,否则会编译不通过。其次宏不是语句,所以末尾没有分号

3.宏函数

3.1 基本使用

宏函数也是宏替换的一种,重点也是替换,只是不同的是,宏函数后面的表达式需要计算出来.如下所示:

#include<iostream>
#define MAX(a,b) ((a)>(b)?(a):(b))

using namespace std;

int main() {
	int res = MAX(1,3);
	cout << "the result is: " << res << endl;
}

运行结果:
在这里插入图片描述
在上面的代码中,我们使用宏函数的方式定义了一个求最大值的宏函数,在前面我们看到了做替换的时候会把我们定义的宏替换到代码中,这时候优先级就会发生改变,所以当我们定义宏函数时尽量在每个参数上加上括号。另外宏函数可以忽略类型:MAX(1,3),MAX(1.1,1.3),MAX('A','B')都是合法的。

3.2 宏替换的多行写法

前面我们介绍的宏函数都是单行定义的,那么假设我们的宏函数有多行应该怎么写呢?写法和实际写函数的时候有一点区别,换行的时候需要加反斜杠"\"分隔,如下所示:

#include<iostream>
#define SWAP(a,b)do{\
int temp = (a);\
(a) = (b);\
(b) = temp;\
}while(0);

using namespace std;
int main() {
	int a = 1;
	int b = 3;
	cout << "before swap: a=" << a <<" b="<< b << endl;
	SWAP(a,b);
	cout << "after swap: a=" << a << " b=" << b << endl;
}

运行结果:
在这里插入图片描述

在上面的代码中,我们定义宏函数时有多行时需要使用反斜杠隔开,在代码中我们还能看到有do{}while(0)的这种写法,也可以使用if(1){}代替以前看开源库中的代码时比较好奇为啥这样写,后面发现这样写的原因是因为防止做宏替换的时候和其他的代码产生冲突。

4.针对宏替换做的条件编译

条件编译主要是用来按照我们事先设置好的条件编译我们的代码,在实际的应用场景中主要是为了做兼容性处理,我们先看一段代码:

#include<iostream>
using namespace std;
int main() {
#if 1
	cout << "条件编译" << endl;
#else
	cout << "不成立,不编译" << endl;
#endif
}

我们通过if后面的条件可以让编译器在编译期间判断条件是否成立,从而进入对应的代码块执行代码条件编译是在程序运行之前完成的,充当条件编译的变量必须是全局变量或者宏,因为局部变量在编译时是没有分配内存的

另外,如果需要判断宏定义xxx不存在可以使用:#ifndef xxx 判断存在则用:#ifdef xxx 这种写法可以防止重复定义宏导致冲突。如果我们想取消宏的定义,可以使用:#undef xxx ,这样就可以取消宏xxx的定义了,取消后xxx自然也就无法使用了。

5.特殊命令和特殊宏

在读别人写的大型项目代码时,我们可能会在宏函数定义中看到两个符号"#" 和“##”,这两个符号都具有特殊的作用,#号可以将输入的内容转换成字符串,如下所示:

#include<iostream>
#define toString(x) #x
using namespace std;

enum Person {
	MAN,
	WOMAN
};
int main() {
	cout << "男人: " << toString(MAN) << " 女人:" << toString(WOMAN) << endl;
}

在上面的代码中,我们将枚举类型的数据转换成立字符串的数据并且输出。读者可以运行看效果
技巧: 我们可以使用这种方式将其他类型的数据转换成字符串数据

接下来就是##,这个命令是连接符,看下面的例子:
在这里插入图片描述
上面是我在项目中看到的实际应用,就是拼接生成一个具有标识作用的名字,用起来特别方便:
在这里插入图片描述
然后我们可能还会看到一些特殊宏,如下面示例:

#include<iostream>
using namespace std;

int main() {
	cout << "日期: " << __DATE__ <<endl<< "时间: "
		<< __TIME__<<endl << "当前行号:" << __LINE__ << endl;
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1143022.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

71 搜索二维矩阵

搜索二维矩阵 题解1 Z字查找(tricky)题解2 一次二分查找题解3 两次二分查找 给你一个满足下述两条属性的 m x n 整数矩阵&#xff1a; 每行中的整数从左到右按非严格递增顺序排列。 每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target &#xff0c;如果 target …

OpenAI 组建安全 AGI 新团队!应对AI“潘多拉魔盒”

夕小瑶科技说 原创 作者 | 小戏 一旦谈及未来 AI&#xff0c;除了天马行空的科幻畅想&#xff0c;不可避免的也有未来 AI 时代的末日预言。从 AI 武器化到 AI 欺骗&#xff0c;从邪恶 AI 到 AI 掌权&#xff0c;人工智能&#xff0c;尤其是通用人工智能的风险始终都清清楚楚的…

nrf52832 开发板入手笔记:资料搜集

前言 最近翻箱&#xff0c;发现了两块几年前买的 NRF52832 与 NRF52840 的开发板&#xff0c;打算搭个 BLE 的开发环境 NRF52832 与 NRF51822 之前用过&#xff0c; NRF52840 没有用过&#xff0c;好像是 BLE4 与 BLE5 的区别吧 相关介绍 除了开发板&#xff0c;最重要的还是…

有线网卡通过无线网卡使其它设备上网

我现在的网络是无线路由器连接公网&#xff0c;电脑上的无线网卡连接路由器使电脑上网&#xff0c;这是完全正常的连接方式。 我现在又有了一台嵌入式设备&#xff0c;它只有有线网口&#xff0c;所以就只能用有线的方式连网&#xff0c;但是我的无线路由器不在电脑旁边&#x…

【23种设计模式】依赖倒置原则

个人主页&#xff1a;金鳞踏雨 个人简介&#xff1a;大家好&#xff0c;我是金鳞&#xff0c;一个初出茅庐的Java小白 目前状况&#xff1a;22届普通本科毕业生&#xff0c;几经波折了&#xff0c;现在任职于一家国内大型知名日化公司&#xff0c;从事Java开发工作 我的博客&am…

openpnp - 程序发布包的制作

文章目录 openpnp - 程序发布包的制作概述笔记程序发布 - 简易打包备注程序发布 - 用install4j来打包END openpnp - 程序发布包的制作 概述 openpnp自带了intall4j的安装脚本. 官方说明这是intall4j 8.x的工程. 下载了intall4j 8.x(找不到注册码, 只能是90天试用版) 和 10.x…

小黑子—spring:第二章 注解开发

spring入门2.0 二 小黑子的spring注解开发1. Bean的基本注解开发1.1 注解版本1.2 Component使用和作用范围1.2.1 作用范围等注解使用1.2.2 Component的三个衍生注解 2. Bean依赖注入注解开发2.1 依赖注入相关注解2.2 Autowired扩展 3. 非自定义Bean注解开发4. Bean配置类的注解…

计算机网络【CN】子网划分与子网掩码

一个子网定义(X.X.X.X/n) 子网掩码为 n 个 1&#xff0c;32-n 个 0包含的 IP 地址数&#xff1a;232−n 主机号全 0 表示本网段主机号全 1 表示网段的广播地址可分配的 IP 地址数 :232−&#x1d45b;−2 子网划分原则 满足子网定义子网&#x1d434;1…&#x1d434;&#x…

牛客网刷题-(6)

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…

QT OpenGL (1)2D Painting Example

2D Painting Example 为方便查阅&#xff0c;此文是原网站文档翻译与整理&#xff0c;如有侵权&#xff0c;请与本人联系。 官网 目录 2D Painting Example概述Helper类定义Helper类实现Widget类定义Widget类实现GLWidget类定义GLWidget类实现Window 类定义Window 类实现运行示…

《利息理论》指导 TCP 拥塞控制

欧文费雪《利息原理》第 10 章&#xff0c;第 11 章对利息的几何说明是普适的&#xff0c;任何一个负反馈系统都能引申出新结论。给出原书图示&#xff0c;本文依据于此&#xff0c;详情参考原书&#xff1a; 将 burst 看作借贷是合理的&#xff0c;它包含成本(报文)&#xf…

代码随想录算法训练营第三十五天丨 贪心算法part06

738.单调递增的数字 思路 暴力解法 题意很简单&#xff0c;那么首先想的就是暴力解法了【超时】。 贪心算法 题目要求小于等于N的最大单调递增的整数&#xff0c;那么拿一个两位的数字来举例。 例如&#xff1a;98&#xff0c;一旦出现strNum[i - 1] > strNum[i]的情况…

通过Vue自带服务器实现Ajax请求跨域(vue-cli)

通过Vue自带服务器实现Ajax请求跨域&#xff08;vue-cli&#xff09; 跨域 原理&#xff1a;从A页面访问到B页面&#xff0c;并且要获取到B页面上的数据&#xff0c;而两个页面所在的端口、协议和域名中哪怕有一个不对等&#xff0c;那么这种行为就叫跨域。注意&#xff1a;类…

大厂面试题-Java并发编程基础篇(二)

目录 一、wait和notify这个为什么要在synchronized代码块中&#xff1f; 二、ThreadLocal是什么&#xff1f;它的实现原理呢&#xff1f; 三、基于数组的阻塞队列ArrayBlockingQueue原理 四、怎么理解线程安全&#xff1f; 五、请简述一下伪共享的概念以及如何避免 六、什…

【Qt之控件QKeySequenceEdit】分析及使用

描述 QKeySequenceEdit小部件允许输入一个QKeySequence。 该小部件允许用户选择一个QKeySequence&#xff0c;通常用作快捷键。当小部件获取焦点时&#xff0c;录制将开始&#xff0c;并在用户释放最后一个键后的一秒钟结束。 用户可以使用输入键盘来输入键序列。通过调用get…

迁移学习 - 微调

什么是与训练和微调&#xff1f; 你需要搭建一个网络模型来完成一个特定的图像分类的任务。首先&#xff0c;你需要随机初始化参数&#xff0c;然后开始训练网络&#xff0c;不断调整参数&#xff0c;直到网络的损失越来越小。在训练的过程中&#xff0c;一开始初始化的参数会…

matlab创建矩阵、理解三维矩阵

1.创建矩阵 全0矩阵&#xff1a;a zeros(2,3,4) 全1矩阵&#xff1a;a ones(2,3,4) &#xff01;和python不一样的地方&#xff01;此处相当于创建了4页2行3列的矩阵&#xff0c;而在python里是2页3行4列。 对第1页的第2行第3列元素进行修改&#xff1a;

【中国知名企业高管团队】系列49:VIVO

今天为您介绍蓝绿两厂的蓝厂——VIVO。这两家公司同源于步步高&#xff0c;两家公司除了名字都是四个字以外&#xff0c;其他方面也实在是太像了&#xff0c;就连核心价值观的前两个词都一样&#xff1a;本分、用户导向。 一、VIVO公司简介 和OPPO一样&#xff0c;VIVO也来源…

[微信小程序踩坑]微信小程序editor富文本组件渲染字符串时,内部图片超出大小导致无法正常渲染或回显(数据传输长度为 3458 KB,存在有性能问题!)

坑一&#xff1a;回显问题 富文本组件&#xff1a; <editor id"editor" name"{{name}}" style"font-size: 28rpx;color: #C9CDD4" read-only"{{true}}" placeholder"{{placeholder}}" bind:input"onChange11"…

Java实现大学兼职教师管理系统 开源

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容三、界面展示3.1 登录注册3.2 学生教师管理3.3 课程管理模块3.4 授课管理模块3.5 课程考勤模块3.6 课程评价模块3.7 课程成绩模块3.8 可视化图表 四、免责说明 一、摘要 1.1 项目介绍 大学兼职教师管理系统&#xff0c;旨…