C语言中宏定义和函数的取舍

宏定义函数与普通函数的区别 可以在前面的系列文章中看到,FreeRTOS 的 头文件中定义了大量的宏定义函数。单单从形式看宏定义的函数和普通函数并无太大的区别,但事实上两者还是有很大不同。 阅读详情

要写好C语言,漂亮的宏定义是非常重要的。宏定义可以帮助我们防止出错,提高代码的可移植性和可读性等。
在软件开发过程中,经常有一些常用或者通用的功能或者代码段,这些功能既可以写成函数,也可以封装成为宏定义。那么究竟是用函数好,还是宏定义好?这就要求我们对二者进行合理的取舍。

我们来看一个例子,比较两个数或者表达式大小,首先我们把它写成宏定义:

#define MAX( a, b) ( (a) > (b) (a) : (b) )

其次,把它用函数来实现:

int max( int a, int b)
{
return (a > b a : b)
}

很显然,我们不会选择用函数来完成这个任务,原因有两个:首先,函数调用会带来额外的开销,它需要开辟一片栈空间,记录返回地址,将形参压栈,从函数返回还要释放堆栈。这种开销不仅会降低代码效率,而且代码量也会大大增加,而使用宏定义则在代码规模和速度方面都比函数更胜一筹;其次,函数的参数必须被声明为一种特定的类型,所以它只能在类型合适的表达式上使用,我们如果要比较两个浮点型的大小,就不得不再写一个专门针对浮点型的比较函数。反之,上面的那个宏定义可以用于整形、长整形、单浮点型、双浮点型以及其他任何可以用“>”操作符比较值大小的类型,也就是说,宏是与类型无关的。

和使用函数相比,使用宏的不利之处在于每次使用宏时,一份宏定义代码的拷贝都会插入到程序中。除非宏非常短,否则使用宏会大幅度增加程序的长度。
还有一些任务根本无法用函数实现,但是用宏定义却很好实现。比如参数类型没法作为参数传递给函数,但是可以把参数类型传递给带参的宏。

看下面的例子:

#define MALLOC(n, type) /
( (type *) malloc((n)* sizeof(type)))

利用这个宏,我们就可以为任何类型分配一段我们指定的空间大小,并返回指向这段空间的指针。我们可以观察一下这个宏确切的工作过程:

int *ptr;
ptr = MALLOC ( 5, int );

将这宏展开以后的结果:

ptr = (int *) malloc ( (5) * sizeof(int) );

这个例子是宏定义的经典应用之一,完成了函数不能完成的功能,但是宏定义也不能滥用,通常,如果相同的代码需要出现在程序的几个地方,更好的方法是把它实现为一个函数。

下面总结和宏和函数的不同之处,以供大家写代码时使用,这段总结摘自《C和指针》一书。

属性

#define宏

函数

代码长度

每次使用时,宏代码都被插入到程序中。除了非常小的宏之外,程序的长度将大幅度增长

函数代码只出现于一个地方:每次使用这个函数时,都调用那个地方的同一份代码

执行速度

更快

存在函数调用、返回的额外开销

操作符优先级

宏参数的求值是在所有周围表达式的上下文环境里,除非它们加上括号,否则邻近操作符的优先级可能产生不可预料的结果。

函数参数只在函数调用时求值一次,它的结果值传递给函数。表达式的求值结果更容易预测。

参数求值

参数用于宏定义时,每次都将重新求值,由于多次求值,具有副作用的参数可能会产生不可预测的结果。

参数在函数调用前只求值一次,在函数中多次使用参数并不会导致多次求值过程,参数的副作用并不会造成任何特殊问题。

参数类型

宏与类型无关,只要参数的操作是合法的,它可以用于任何参数类型。

函数的参数是与类型有关系的,如果参数的类型不同,就需要使用不同的函数,即使它们执行的任务是相同的。

 
宏定义和函数调用的区别 详细罗列出宏定义和函数调用的区别,很全。。。 立即下载

相关推荐

Geant4 学习笔记(一):实现multi-thread多线程

简单修改实现Geant4多线程

weixin_52417815的博客 6084

宏与函数的对比、内联函数

大幅度增加程序的长度优先级的问题给个图片易于你做比较:由上述介绍,可以知道宏和函数都有它们特定的优缺点,那么有没有一种方法可以将两者的优点结合起来呢?答案是有的——内联函数。

2201_75479723的博客 1092

L298N电机驱动模块的接线使用与代码实现

#include "iostm8s208mb.h" #define u8 uint8_t #define u16 uint16_t #define u32 uint32_t typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned long uint32_t; // 关于LED灯的宏定义 #define LED2 PI_ODR_ODR2 //输出量 #define LE

Clichong 13万+

C语言中宏定义和函数的区别

前言 在C语言中,对于一些常用或通用的代码段的封装可以有两种方式:函数和宏定义。 这篇博客就来带大家梳理一下对于这两种方式我们在使用时应该如何抉择,以及它们的区别和优缺点。 宏定义和函数的区别 从程序的执行来看: 函数调用需要开辟和释放栈空间带来开销(压栈、释放),不仅会降低代码效率,而且代码量也会大大增加。 宏定义只在编译前进行,不分配空间,不占运行时间。 总结:宏定义在代码规模和速度方面都比函数更胜一筹 从参数的类型来看: 函数的参数必须声明为一种特定的数据类型,如果参数的类型不同,就需要使用不

Outtch_的博客 1794

机器学习-深嵌交叉验证(Nested Cross-Validation)

Section I: Code and Analyses 第一部分:代码 from sklearn import datasets from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.svm import SVC from...

Santorinisu Blogs 2716

实战指南:CentOS 7下VOS3000 8.0从零部署到授权激活全流程

本文提供了一份详尽的CentOS 7系统下部署VOS3000 8.0的实战指南。从环境准备、使用FileZilla上传安装包、执行自动化安装脚本,到获取软件码、利用注册机生成授权文件并激活,手把手带领用户完成从零部署到投入商用的全流程,确保系统稳定运行。

zero1的博客 895

[转]宏定义和函数调用的区别

含参数的宏与函数的区别 ?宏替换不占运行时间,只占编译时间;而函数调用则占运行时间(分配单元、保留现场、值传递、返回),所以每次执行都要载入所以执行起来比较慢一些。。 ?定义宏的时候不要在宏及其参数之间键入空格,因为宏替换的时候会把你不经意打的空格当作宏的一部分进去。 ?在宏定义中把每个参数都用括号括起来,同时把整个结果也用括号(对于单个...

weixin_30449453的博客 1086

ISO26262功能安全--产品开发过程

目录 1.总体理解 2.概念阶段——吹牛,我们是打草稿的 2.1 相关项定义 2.2 HARA分析 2.3 功能安全目标 2.4 安全需求与安全概念 3. 系统阶段——闭门造神车,我们开始修炼 3.1 技术安全需求(TSC) 3.2 系统架构设计 3.3 安全分析与独立性分析 3.4 软硬件接口(HSI) 4. 硬件阶段——苦其心志,苦练经骨 4.1 硬件架构...

AgingMoon的博客 1万+

c语言中宏定义和函数的取舍

要写好C语言,漂亮的宏定义是非常重要的。宏定义可以帮助我们防止出错,提高代码的可移植性和可读性等。 在软件开发过程中,经常有一些常用或者通用的功能或者代码段,这些功能既可以写成函数,也可以封装成为宏定义。那么究竟是用函数好,还是宏定义好?这就要求我们对二者进行合理的取舍。我们来看一个例子,比较两个数或者表达式大小,首先我们把它写成宏定义:#define MAX( a, b) ( (a)

350

Unity Scriptable Build Pipeline (SBP) 详解

Unity 的可编程构建管线(Scriptable Build Pipeline, SBP)标志着引擎构建架构的一次关键转变,它从不透明的 C++ 实现转向了灵活、可扩展的 C# 框架。SBP 旨在满足现代游戏开发日益增长的需求,通过改进增量处理和高效缓存机制显著提升了构建性能。它赋予开发者对内容构建过程前所未有的控制力,从而能够针对特定项目需求进行深度定制。尽管 SBP 是 Unity 推荐的 Addressables 系统的重要基础层,但理解其核心组件、构建流程和高级功能对于优化大型项目、简化 CI/C

m0_57771536的博客 2208

海康VM加密狗无法识别常见问题排查

海康VM加密狗无法识别常见问题排查

视觉人机器视觉的博客 2712

C/C++预处理器指令与宏定义同函数调用的深度解析

特性宏定义函数调用处理阶段预处理阶段文本替换编译后生成可执行代码类型检查无严格的类型检查参数求值可能多次求值(副作用风险)只求值一次调试支持不可调试支持断点调试代码生成每次调用生成重复代码单一代码副本预处理器指令为C/C++提供了强大的元编程能力,但也需要谨慎使用以避免潜在陷阱。考虑因素推荐方案类型安全函数/模板性能关键路径内联函数/谨慎使用宏代码可维护性避免复杂宏跨平台需求合理使用条件编译。

llookl的博客 789

整车CAN网络错误帧排查方法

本文围绕 CAN 总线错误帧展开,先剖析其产生原因,涵盖物理连接与硬件问题、电磁兼容性问题、总线负载与设计问题及配置问题;再阐述位错误、填充错误等 5 类错误帧类型;接着说明错误帧与总线 BUSOFF 的关系,解析主动 / 被动错误状态及 BUSOFF 的触发与恢复;还结合整车故障案例做实际分析,指出错误帧根源多为线束或控制器问题。最后总结,强调错误帧是 CAN 协议保障高鲁棒性的机制,掌握相关知识助工程师提升 CAN 网络处理能力。

车载网络小D的博客 1247

C语言宏定义和宏定义函数

C语言宏定义和宏定义函数  要写好C语言,漂亮的宏定义是非常重要的。宏定义可以帮助我们防止出错,提高代码的可移植性和可读性等。   在软件开发过程中,经常有一些常用或者通用的功能或者代码段,这些功能既可以写成函数,也可以封装成为宏定义。那么究竟是用函数好,还是宏定义好?这就要求我们对二者进行合理的取舍。   我们来看一个例子,比较两个数或者表达式大小,首先我们把它写成宏定义:

4428

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

C语言宏定义函数的使用(定义单行和多行)

    要写好C语言,漂亮的宏定义是非常重要的。宏定义可以帮助我们防止出错,提高代码的可移植性和可读性等。   在软件开发过程中,经常有一些常用或者通用的功能或者代...

欲盖弥彰1314 6269

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

C语言【宏定义与函数的区别】

宏与函数的区别 属性 #define 宏 函数 代码长度 每次调用时,宏代码都会被插入到程序中。除了非常小的 宏之外,程序的长度将大幅增加 函数代码只出现在一个地方,每次调用这个函数时, 调用的都是那个地方的同一份代码 执行速度 更快 存在函数调用/返回的额外开销 操作符优先级 宏参数的求值是在所有周围下上文环境里,除非给它们加 上括号,否则邻近操作符的优先级,可能会产生不可预测的结果 函数参数只在函数调...

m0_50668851的博客 3420

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

上一篇: GNU C 扩展(二)
下一篇: 宏定义函数指针类型&函数返回左值类值
pointfish
博客等级 码龄17年 58粉丝 11原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值