关于#define的一些小知识
目录
一,#define的声明格式:
二,#define宏的作用是为了完成替换
#define的替换规则:
三,#define使用时常犯的错误
四,宏与函数的比较
4.1,什么时候使用宏?
4.1,使用宏的好处与坏处
4.3宏的奇怪用法
一,#define的声明格式:
#define name( parament-list ) stuff
关于#define格式需要注意的几个点:
1.在stuff后面不能有冒号
2.name要和左圆括号紧贴在一起
🌰:使用#define定义一个 求两者间较大值的宏:
#define MAX(a,b) a>b?a:b
二,#define宏的作用是为了完成替换
#define的替换规则:
1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。
比如以下代码:
#define MAX(a,b) a>b?a:b
#include<stdio.h>
int main() {int a = 10;int b = 5;printf("%d\n", MAX(a, b));
}
在程序预处理的过程中就会变成这样:
#define MAX(a,b) a>b?a:b
#include<stdio.h>
int main() {int a = 10;int b = 5;printf("%d\n",a>b?a:b);//MAX(a,b)直接被替换掉
}
这也就解释了为什么在宏定义语句的末尾为什么不能加 ;(分号),假如我在宏定义后面加了分号:
#define MAX(a,b) a>b?a:b;
那在替换过程中,MAX(a,b)就会被替换成这样:
a>b?a:b;
#define MAX(a,b) a>b?a:b
#include<stdio.h>
int main() {int a = 10;int b = 5;printf("%d\n",a>b?a:b;);//明显就是一个错误的代码
}
所以我们便不能在宏定义后面随意加上;(冒号)。
三,#define使用时常犯的错误
3.1不加括号:
#define MUL(a,b) a*b //参数不加括号
现在我让a=2+1,b=2+1代入下列代码中:
#include<stdio.h>
#define MUL(a,b) a*b
int main() {int c = MUL(2+1, 2+1);printf("%d\n", c);return 0;
}
结果:5
但是我们都知道3*3等于9,所以这个代码为什么会错呢?
原因其实很简单,因为宏会直接替换,也就是宏其实是不会计算的。 所以这段宏就会被替换成这样:
#define MUL(2+1,2+1) 2+1*2+1//c=2+1*2+1=5
int main() {int c = MUL(2+1, 2+1);printf("%d\n", c);//c=5return 0;
}
所以结果就变成5了。
在这里做一个小小的改动:
#include<stdio.h>
#define MUL(a,b) (a)*(b)//加两个括号
int main() {int c = MUL(2+1, 2+1);printf("%d\n", c);return 0;
}
于是宏替换就会变成这个样子:
#define MUL(2+1,2+1) (2+1)*(2+1)//c=(2+1)*(2+1)=9
int main() {int c = MUL(2+1, 2+1);printf("%d\n", c);//c=5return 0;
}
输出:9
但是仅仅做到这样有时候是不保险的:
比如:
🌰:
#define MUL(a,b) (a)+(b)
#define MUL(a,b) (a)+(b)
int main() {int c = 10*MUL(3, 3);//计算的值应该是60printf("%d\n", c);return 0;
}
但是:
输出:33
因为在这里宏替换以后,宏会变成这样:
#define MUL(a,b) (3)+(3)
int main() {int c = 10*(3)+(3);//相当于10*3+3==33printf("%d\n", c);return 0;
}
在这里就有一个解决方案:
#define MUL(a,b) ((a)+(b))//再加一个大括号
int main() {int c = 10*MUL(3, 3);//计算的值应该是60printf("%d\n", c);return 0;
}
这样就可以得到我们想要的60了。
四,宏与函数的比较
4.1,什么时候使用宏?
在这里我们有一个基本的常识:
1.实现简单的功能时使用宏。
比如:求两个数的较大值
#define MAX(a,b) ((a)>(b)?(a):(b))2.实现复杂功能时用函数。
4.1,使用宏的好处与坏处
好处:
1.宏在小型程序中执行的时候更加有效率
2.宏是没有类型的,所以调用的时候更加方便
坏处:
1.无法调试
2. 每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序 的长度。
4.3宏的奇怪用法
比如使用 malloc这个函数:
正常使用:
#include<stdio.h> #include<stdlib.h> int main() {int* arr = (int*)malloc(20);if (*arr == NULL) {perror("malloc:");return; }//使用//关闭free(arr);arr = NULL;return 0; }
使用宏:
先定义宏:
#define MALLOC(type,nums) (type)malloc(nums*sizeof(type))
然后就可以这样使用:
#include<stdio.h>
#include<stdlib.h>
#define MALLOC(type,nums) (type)malloc(nums*sizeof(type))
int main() {int* arr = MALLOC(int*,20);if (*arr == NULL) {perror("malloc:");return;}//使用//关闭free(arr);arr = NULL;return 0;
}
今天分享完毕。。。。
相关文章:
关于#define的一些小知识
目录 一,#define的声明格式: 二,#define宏的作用是为了完成替换 #define的替换规则: 三,#define使用时常犯的错误 四,宏与函数的比较 4.1,什么时候使用宏? 4.1,…...
rabbitmq普通集群与镜像集群搭建
1.准备三台centos7主机,并关闭防火墙与selinux 2.安装rabbitmq环境必备的Erlang(以下所有操作三台主机均需要执行) 执行以下命令下载配置erlang yum源 curl -s https://packagecloud.io/install/repositories/rabbitmq/erlang/script.rpm.sh | sudo bash使用yum命…...
session和jwt哪个更好
session和jwtsession优点缺点jwt优点缺点总结session 优点 原理简单,易于学习。用户信息存储在服务端,可以快速封禁某个用户。 缺点 占用服务端内存,硬件成本高。多进程,多服务器时,不好同步-需要使用第三方缓存&a…...
基于TPU-MLIR实现UNet模型部署-决赛答辩02
队伍:AP0200023 目录 初赛 一、 模型导出优化 1.1 直接倒出原始模型并转换 1.2 导出模型前处理 1.2.1 导出Resize 1.2.2 导出归一化 1.3导出模型后处理 1.3.1导出 Resize 与 1.3.2导出 ArgMaxout 1.3.3导出特征转RGB 复赛 一、 确定baseline 二、优化模…...
Maven高级-分模块开发依赖管理
Maven高级-分模块开发&依赖管理1,分模块开发1.1 分模块开发设计1.2 分模块开发实现1.2.1 环境准备1.2.2 抽取domain层步骤1:创建新模块步骤2:项目中创建domain包步骤3:删除原项目中的domain包步骤4:建立依赖关系步骤5:编译maven_02_ssm项目步骤6:将项目安装本地…...
《安富莱嵌入式周报》第308期:开源带软硬件安全认证的PLC设计,开源功率计,可靠PID实现,PR2机器人设计文件全开源,智能手表设计WASP-OS
周报汇总地址:嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 视频版: https://www.bilibili.com/video/BV1F24y157QE 《安富莱嵌入式周报》第308期:开源带软…...
代码随想录算法训练营第五十六天 | 583. 两个字符串的删除操作、72. 编辑距离、编辑距离总结
583. 两个字符串的删除操作 动规五部曲 1、确定dp数组(dp table)以及下标的含义 dp[i][j]:以i-1为结尾的字符串word1,和以j-1位结尾的字符串word2,想要达到相等,所需要删除元素的最少次数。 2、确定递推…...
Sip协议
简介 SIP(Session Initiation Protocol,会话初始协议)是一个用于建立、更改和终止多媒体会话的应用 层控制协议,其中的会话可以是 IP 电话、多媒体会话或多媒体会议。SIP 是 IETF 多媒体数据和控 制体系结构的核心协议࿰…...
RandomAccessFile类 断点续传
文章目录学习链接RandomAccessFile构造方法实现的接口DataOutputDataInputAutoCloseable重要的方法多线程读写同一个文件(多线程复制文件)代码1代码2断点续传FileUtils学习链接 RandomAccessFile详解 Java IO——RandomAccessFile类详解 java多线程-断点…...
SpringCloud微服务技术栈的注册中心Eureka
文章目录SpringCloud微服务技术栈的注册中心Eureka简介Eureka特点操作步骤环境准备创建Eureka Server注册服务提供方调用服务消费方总结SpringCloud微服务技术栈的注册中心Eureka 简介 在微服务架构中,服务的数量庞大,而且每个服务可能会有多个实例。此…...
Unity最新热更新框架 hybridclr_addressable
GitHub:YMoonRiver/hybridclr_addressable: 开箱即用的商业游戏框架,集成了主流的开发工具。将主流的GameFramework修改,支持Addressable和AssetBundle,已完善打包工具和流程。 (github.com) # 新增GameFramework Addressables 开箱即用 # 新…...
【c语言】一维数组***特性、存储原理
创作不易,本篇文章如果帮助到了你,还请点赞支持一下♡>𖥦<)!! 主页专栏有更多知识,如有疑问欢迎大家指正讨论,共同进步! 给大家跳段街舞感谢支持!ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ…...
[oeasy]python0133_[趣味拓展]好玩的unicode字符_另类字符_上下颠倒英文字符
另类字符 回忆上次内容 上次再次输出了大红心♥ 找到了红心对应的编码黑红梅方都对应有编码 原来的编码叫做 ascii️ \u这种新的编码方式叫unicode包括了 中日韩字符集等 各书写系统的字符集 除了这些常规字符之外 还有什么好玩的东西呢? 颠倒字符 这个网站可以…...
找凶手,定名次,字符串旋转,杨氏矩阵
1.找凶手问题: //题目名称: //猜凶手 //题目内容: //日本某地发生了一件谋杀案,警察通过排查确定凶手必为4个嫌疑犯的一个。 //以下为4个嫌疑犯的供词: //A说:不是我 //B说:是C //C说ÿ…...
Python 进阶指南(编程轻松进阶):十四、实践项目
原文:http://inventwithpython.com/beyond/chapter14.html 到目前为止,这本书已经教会了你编写可读的 Python 风格代码的技巧。让我们通过查看两个命令行游戏的源代码来实践这些技术:汉诺塔和四人一排。 这些项目很短,并且基于文…...
Redis的五种数据类型及应用场景
Redis是一个开源的key-value数据库。 五种数据类型 String,List, Set,SortedSet,Hash List类型可以存储多个String。 Set类型可以存储不同的String。 SortedSet可以存储String的排序。 Hash可以存储多个key-value对。 String …...
c++List的详细介绍
cList详细使用 write in front 作者: 不进大厂不改名 专栏: c 作者简介:大一学生 希望能向其他大佬和同学学习! 本篇博客简介:本文主要讲述了一种新容器list的使用方法,相信你在学了后,能够加深…...
Heap堆的升序排序
在heap堆中,大根堆是一种特殊的堆,它满足下列性质:对于任意一个非叶子节点i,其左右子节点的值均小于等于它本身的值。 在大根堆中,堆顶元素永远是值最大的元素,所以将堆顶元素不断取出来,就相当…...
小程序开发收费价目表
小程序作为一种新兴应用形式,正在逐渐成为企业和个人推广、运营的重要手段。然而,小程序开发的价格因项目规模和复杂程度差异较大,令不少人望而却步。本文将从小程序开发的相关因素入手,探讨小程序开发的价格范围和算法。 一、小…...
Dubbo服务暴露步骤详解
文章目录Dubbo服务暴露步骤详解背景介绍理论知识讲解什么是服务暴露?Dubbo 服务暴露的基本原理操作步骤具体实现环境准备实现服务接口实现服务提供者配置 Dubbo 服务提供者启动服务提供者实现服务消费者配置 Dubbo 服务消费者测试总结Dubbo服务暴露步骤详解 背景介…...
多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...
【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...
4. TypeScript 类型推断与类型组合
一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式,自动确定它们的类型。 这一特性减少了显式类型注解的需要,在保持类型安全的同时简化了代码。通过分析上下文和初始值,TypeSc…...
【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅
目录 前言 操作系统与驱动程序 是什么,为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中,我们在使用电子设备时,我们所输入执行的每一条指令最终大多都会作用到硬件上,比如下载一款软件最终会下载到硬盘上&am…...
消息队列系统设计与实践全解析
文章目录 🚀 消息队列系统设计与实践全解析🔍 一、消息队列选型1.1 业务场景匹配矩阵1.2 吞吐量/延迟/可靠性权衡💡 权衡决策框架 1.3 运维复杂度评估🔧 运维成本降低策略 🏗️ 二、典型架构设计2.1 分布式事务最终一致…...
