C语言中,定义宏求两个数的最大值\最小值

前言

        之前笔试过程中,我自认为使用宏来求得最值这方面已经了解的足够清楚。我一直是使用下面两个宏来做题的。直到我最近闲暇下来,阅读了《嵌入式C语言自我修养》这本书,才发现自己很多情形没有考虑到位。

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

一、同类型的变量,如果出现对参数自增自减操作,该如何修改

如果按照前言的版本,显然在下面的情况是无法正常运行的

#define MAX(x,y) ((x) > (y) ? (x) : (y))
int main(void)
{int i = 2;int j = 6;printf("max=%d",MAX(i++,j++));  //此处运行后i=4,j=7;且max=7;return 0;
}

        该测试代码期待的运行结果是,i、j两个变量进行对比,max存储i、j未自增前的最大值,而经过MAX宏运算后,i、j各自自增1,即期待的运行后结果为max = 6, i = 3,j=7。

        与期待的结果不同,实际运行的结果为max = 7, i =4 ,j=7。

        为什么会出现这个状况呢,显然是进行宏替换时,将自增运算符也替换了,如下面代码所示。

#define MAX(x,y) ((x) > (y) ? (x) : (y))
int main(void)
{int i = 2;int j = 6;//printf("max=%d",MAX(i++,j++));printf("max=%d",((i++) > (j++) ? (i++) : (j++)));    //宏替换后的代码return 0;
}

        显然我们无法要求宏的使用者都不使用自增运算符,那么如何解决这个bug呢?解决这个问题的关键是让三元运算符表达式部分不被替换成自增自减运算符即可。这里使用新建一个表达式来解决。

#define MAX(x,y) ({      \int _x = (x);        \int _y = (y);        \_x > _y ? _x : _y;   \
})int main(void)
{int i = 2;int j = 6;printf("max=%d",MAX(i++,j++));return 0;
}

     在宏定义中,新建表达式将x、y存起来,在使用新建的变量_x、_y来进行比较即可解决这个bug。新建表达式后,_x\_y存储的是未自增前的x\y表达式的值;而x\y表达式被赋值给_x\_y后,x\y表达式其中如果有自增自减运算符则会运行,而后的比较部分没有调用到x\y表达式,即x\y表达式不会宏替换导致多次自增自减。

        至此,同类型变量下, 参数包含自增自减运算符导致多次自增自减的bug消除了。那么能否泛化一下,使其宏定义中可以指定其他类型的变量呢?

二、修改宏对比中参数的类型

        上一节结尾提到,宏定义中创建的_x\_y变量均为int类型,难不成float、char等类型要对比都需要重复写对比宏吗?这一小节来将对比宏进行泛化,不指定对应的类型。

        最简单的解决思路是,宏中新增一个变量,传入要对比参数的类型,这样就很简单解决了。

#define MAX(type,x,y) ({  \type _x = (x);        \type _y = (y);        \_x > _y ? _x : _y;    \
})int main(void)
{int i = 2;int j = 6;printf("max=%d\n",MAX(int,i++,j++));printf("max=%f\n",MAX(float,3.14,3.15));return 0;
}

        通过传入宏参数的类型显然很方便,但是就是要偷懒,就是不想手动传入类型该如何做呢?

三、推断变量类型

        C语言里面有typeof可以来获取变量的类型,这里同样可以使用。

#define MAX(x,y) ({       \typeof(x) _x = (x);   \typeof(y) _y = (y);   \_x > _y ? _x : _y;    \
})int main(void)
{int i = 2;int j = 6;printf("max=%d\n",MAX(i++,j++));printf("max=%f\n",MAX(3.14,3.15));return 0;
}

        但显然这里存在一个问题,如果x,y变量类型不一致怎么办,是否能够智能提醒变量类型不一致呢?

四、变量类型匹配提醒

#define MAX(x,y) ({       \typeof(x) _x = (x);   \typeof(y) _y = (y);   \(void) (&_x == &_y); \_x > _y ? _x : _y;    \
})

        在宏定义中,我们添加了(void)(&_x == &_y)进行类型的对比,那么这里是如何起作用的呢?

        c语言编译器当检测到不同类型的指针进行比较时,编译器会发出一个警告,这样就可以提示到用户:你当前用两个不同类型的变量运行MAX\MIN宏。而前面添加(void)的原因是,当两个变量是同样类型时,比较过程会提示一个warning,加上(void)后,可以消除该警告。

        到此,最大最小宏的编程之旅到此结束,希望阅读到这里的读者有所收获。

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

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

相关文章

银川岗位外包找邦芒 一站式企业外包解决方案

在当今日益多变和竞争激烈的市场环境中&#xff0c;岗位外包作为一种高效、灵活的用工方式&#xff0c;已逐渐成为企业应对业务波动、降低风险成本的首选策略。银川邦芒人力凭借其丰富的经验和专业的服务&#xff0c;为企业提供了卓越的岗位外包解决方案。 为何选择岗位外包&am…

正大国际期货:如何做恒指期货

要想获得较好的收益&#xff0c;就必须要知道恒指做单的技巧&#xff0c;毕竟掌握了技巧才是最重要的。 第一、下单之前一定看准行情并且顺势操作。何为顺势&#xff1f;就是我们平时说的趋势&#xff0c;只要趋势做对了&#xff0c;在中途可能会有一些起伏&#xff0c;但是最后…

中间件复习之-分布式存储系统

单机存储系统介绍 存储引擎&#xff1a;存储系统的发动机&#xff0c;提供数据的增、删、改、查能力&#xff0c;直接决定存储系统的功能&#xff08;支持怎么样的查询&#xff0c;锁能锁到什么程度&#xff09;和性能&#xff08;增删改查速度&#xff09;。 性能因素 写入方…

计算机网络知识CIDR(无类别域区间路由)

目录 介绍 基本信息 优点与关联 如何计算判定范围&#xff08;你应该是来看这个的&#xff0c;前面是水字数的&#xff09; 省流版 介绍 无类别域间路由&#xff08;Classless Inter-Domain Routing、CIDR&#xff09;是一个用于给用户分配IP地址以及在互联网上有效地路由…

智慧监狱大数据整体解决方案(51页PPT)

方案介绍&#xff1a; 智慧监狱大数据整体解决方案通过集成先进的信息技术和大数据技术&#xff0c;实现对监狱管理的全面升级和智能化改造。该方案不仅提高了监狱管理的安全性和效率&#xff0c;还提升了监狱的智能化水平&#xff0c;为监狱的可持续发展提供了有力支持。 部…

transformers库的模型在加载之后,重新设置device_map=auto

from accelerate import infer_auto_device_map, dispatch_modeldevice_map infer_auto_device_map(model, dtypetorch.bfloat16) model dispatch_model(model, device_mapdevice_map)

「小明赠书活动」第五期“网安三剑客”套系图书《内网渗透技术》《渗透测试技术》《Web应用安全》

大模型风潮已掀起&#xff0c;各大巨头争相入局&#xff0c;从ChatGPT到Sora&#xff0c;全球的AI应用“卷出了花”。然而&#xff0c;网络安全人员在享受AI技术带来的便捷之余&#xff0c;也不得不面对一系列新兴的安全挑战&#xff0c;无法忽视。 ⭐️ 赠书 - 图书简介 人…

C#学习系列之UDP同端口发送与接收

C#学习系列之UDP同端口发送与接收 啰嗦解决方案代码总结 啰嗦 项目中需要同一端口的发送与接收&#xff0c;当时一直都没有在同一个程序中对同一个端口进行发送与接收的尝试。 采用的形式是定义两个UdpClient&#xff0c;对同一UDP端口进行收发与接收。结果导致总有一个线程会…

双标引领:汽车软件安全的ASPICE与ISO21434之道

随着汽车行业的飞速发展&#xff0c;尤其是智能化、网联化趋势的加剧&#xff0c;汽车软件开发的复杂性和安全性需求日益提升。在这样的背景下&#xff0c;ASPICE标准和ISO21434安全标准应运而生&#xff0c;为汽车软件的开发和管理提供了坚实的支撑。 ASPICE&#xff08;Auto…

2024.6.7 刷题总结

2024.6.7 **每日一题** 3038.相同分数的最大操作数目 Ⅰ&#xff0c;该题为简单模拟题&#xff0c;先计算出前两个元素的和&#xff0c;依次往后遍历两个元素&#xff0c;若它们和与之前的相同&#xff0c;则答案&#xff0c;若不同则直接跳出&#xff0c;结束。 134.加油站,该…

【解读】核密度图

def&#xff1a;what 核密度估计&#xff08;Kernel Density Estimation&#xff0c;简称KDE&#xff09;是一种用来估计随机变量概率密度函数的非参数方法 实现&#xff1a;&#xff08;库函数&#xff09;how import seaborn as sns import matplotlib.pyplot as plt# 使用…

Web前端讲师简历:专业技能与教学经验的完美结合

Web前端讲师简历&#xff1a;专业技能与教学经验的完美结合 作为一名资深的Web前端讲师&#xff0c;我致力于将我的专业技能和丰富经验传授给每一位学生&#xff0c;帮助他们在Web前端领域取得卓越成就。以下是我的个人简历&#xff0c;详细介绍了我的教育背景、专业技能、教学…

GaussDB技术解读——GaussDB架构介绍(二)

上篇图文&#xff0c;从GaussDB关键架构目标、GaussDB分布式架构、数据计算路由层&#xff08;Coordinator&#xff09;关键技术方案等三方面对GaussDB架构进行了介绍。本篇将从数据持久化存取层(DataNode)关键技术方案、全局事务管理层&#xff08;GTM&#xff09;关键技术方案…

目前常用的后端技术

在后端开发中&#xff0c;有多种技术和框架可供选择&#xff0c;具体取决于项目的需求、团队的技能和经验&#xff0c;以及组织的架构决策。以下是一些常见的后端开发技术和框架&#xff1a; 1. 编程语言 Java&#xff1a; 广泛使用于企业级应用&#xff0c;有大量的库和框架…

企业内网安全软件分享,有什么内网安全软件

内网安全&#xff1f; 其实就是网络安全的一种。 什么是内网安全软件&#xff1f; 内网安全软件是企业保障内网安全的一种重要工具。 它主要帮助企业实现对网络设备、应用程序、用户行为等方面的监控和管理&#xff0c;以预防和应对各种网络攻击。 这类软件主要用于对内网中…

【程序员科科】2024年最新Python+Vue前后端分离全栈课程,05python数据类型字典

当涉及到需要存储一组数据或项目时&#xff0c;Python中的列表类型就显得非常重要了。列表类型允许我们保存多个值&#xff0c;这些值可以是不同类型的数据&#xff0c;比如整数、浮点数、字符串等。 为什么有这个类型? 列表类型允许我们以一种结构化的方式存储和组织数据&am…

轻兔推荐 —— hoppscotch

via&#xff1a;轻兔推荐 - https://app.lighttools.net/ 简介 hoppscotch是一个开源的http调试客户端&#xff0c;界面简洁&#xff0c;功能完善&#xff0c;原名叫postwomen&#xff0c;明显是要跟postman干的&#xff0c;作为postman的替代品就挺合适 - 功能完善&#xff…

java接口设计需要考虑哪些方面

1.签名 目的&#xff1a;防止数据被篡改 &#xff08;1&#xff09;接口请求方将请求参数、时间戳和密钥拼接成一个字符串。 &#xff08;2&#xff09;使用MD5等hash算法生成签名。 &#xff08;3&#xff09;在请求参数或请求头中增加sign参数传递给API接口。 &#xff08;4&…

内部人员随意上传涉密数据,对国家安全造成严重威胁

对数据采取有效措施&#xff0c;守住“云”安全&#xff01; 近年来&#xff0c;随着网络“云”功能不断普及&#xff0c;“云端”数据也成为了境外间谍情报机关关注的重点&#xff0c;他们通过网络攻击、植入木马等各种手段&#xff0c;试图窃取我国敏感信息和涉密数据&#…

企业微信应用 应用号内消息链接无法在企微内置浏览器打开 windows PC客户端 问题解决

问题 需求是每周在企微的应用号上发送周报&#xff0c;周报中会带着进入系统的链接&#xff0c;点击进入可以查看详情。系统需要登录鉴权&#xff0c;因此需要在内置浏览器打开便于自动认证。 但是&#xff0c;在企微应用号发送的链接&#xff0c;手机上可以正常使用企微内置…