宏定义函数-普通函数-内联函数区别

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

宏定义函数VS普通函数VS内联函数

宏定义函数VS普通函数

  1. 宏定义函数
  • 要点:变量都用括号括起来,防止出错,结尾不需要;。在实际编程中,不推荐把复杂的函数使用宏,不容易调试。多行用\

  • 例子:
    单行:
    #define MAX(a, b) ((a) > (b) ? (a):(b))
    多行:

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

    对于第一个函数,如果用普通函数,该怎样写?

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

    很显然,我们不会选择用函数来完成这个任务,原因有两个:

    1. 首先,函数调用会带来额外的开销,它需要开辟一片栈空间,记录返回地址,将形参压栈,从函数返回还要释放堆栈。这种开销会降低代码效率,而使用宏定义则在代码速度方面比函数更胜一筹;
    2. 其次,函数的参数必须被声明为一种特定的类型,所以它只能在类型合适的表达式上使用,我们如果要比较两个浮点型的大小,就不得不再写一个专门针对浮点型的比较函数。反之,上面的那个宏定义可以用于整形、长整形、单浮点型、双浮点型以及其他任何可以用“>”操作符比较值大小的类型,也就是说,宏是与类型无关的。
    3. 和使用函数相比,使用宏的不利之处在于每次使用宏时,一份宏定义代码的拷贝都会插入到程序中。除非宏非常短,否则使用宏会大幅度增加程序的长度。
    4. 还有一些任务根本无法用函数实现,但是用宏定义却很好实现。比如参数类型没法作为参数传递给函数,但是可以把参数类型传递给带参的宏。比如上面的malloc的例子.
  • 总结:

属性#define宏函数
代码长度每次使用时,宏代码都被插入到程序中。除了非常小的宏之外,程序的长度将大幅度增长。函数代码只出现于一个地方:每次使用这个函数时,都调用那个地方的同一份代码
执行速度更快存在函数调用、返回的额外开销
操作符优先级宏参数的求值是在所有周围表达式的上下文环境里,除非它们加上括号,否则邻近操作符的优先级可能产生不可预料的结果。函数参数只在函数调用时求值一次,它的结果值传递给函数。表达式的求值结果更容易预测。
参数求值参数用于宏定义时,每次都将重新求值,由于多次求值,具有副作用的参数可能会产生不可预测的结果。参数在函数调用前只求值一次,在函数中多次使用参数并不会导致多次求值过程,参数的副作用并不会造成任何特殊问题。
参数类型宏与类型无关,只要参数的操作是合法的,它可以用于任何参数类型。函数的参数是与类型有关系的,如果参数的类型不同,就需要使用不同的函数,即使它们执行的任务是相同的。
  1. 补充: 普通函数的调用堆栈情况.
    比如:
    void P(){
        phase 1;
        Q();
        phase 2;
    }
    
    void Q() {
        phase 3;
        R();
        phase 4;
    }
    
    P( ),Q( ),R( )在经过编译器变为汇编后, 都有自己的代码位置,比如
    0x0000400A P:
                xxx     #phase1
                call Q
                xxx     #phase2
                ret
    0x0000400B Q:
                yyy     #phase3
                call R
                yyy     #phase4
    0x0000400C R: 
                zzz     #phase
                zzz     #phase
    
    而对应的栈帧呢:
    ---
    P的参数入栈
    返回地址1(phase2的地址,即函数Q后的一下条语句)
    ---
    Q的参数入栈
    返回地址2(phas4的地址,即函数R后的一下条语句)
    ---
    R的参数
    ---
    
    当R函数调用完毕,则R的栈帧出栈,同时将返回地址2pop,返回给rip,这样就继续执行一下条语句了.Q调用完毕也是同理的,所以这就是普通函数的调用情况.
    很显然,普通函数调用在汇编后,这个函数只有一份代码量,调用它就入栈出栈它的地址,造成一定的开销.而对于宏定义来说,只是简单的文本替换,这在预处理时就替换过了,故实际上你可以认为就没有宏定义出来的函数,所以当然不会有这样的开销.

普通函数VS内联函数 内联函数VS宏

例子:

inline void P() {
    phase P1;
    phase P2;
}

void Q() {
    phase1;
    P();
    phase2;
}

P是一个内联函数,对于Q来说编译后得到的汇编是什么样子呢?

Q:
    xxx     #phase 1
    yyy     #phase P1
    zzz     #phase P2
    xxx     #pahse 2

我们可以发现,Q的汇编代码中并没有对P的调用(call),而是直接将P的代码拷到Q中,这样的好处就是由于没有call ret,所以就没有普通函数调用带来的出栈入栈开销,速度更快,但增加代码量,增加内存开销.

那么内联函数和宏又有哪些不同?
内联函数本质上还是一个函数,只是在调用时不必call ret罢了.

  • 内联函数是一个真正的函数,遵循函数的类型和作用域规则,编译器在调用一个内联函数时,会首先检查它的参数的类型,保证调用正确,这样就消除了它的隐患和局限性;
    即: inline void func(int i,int j);调用这个时候,我必须符合参数类型才能正确调用,而宏直接替换就完事了,是类型无关的.
  • 内联函数可以作为某个类的成员函数,这样就可以在其中使用所在类的保护成员及私有成员;
  • 宏是不加任何验证的简单代码替换,除非万不得已,不要使用。

注意:
内联是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。如果执行函数代码的时间比处理函数调用机制的时间长,则节省的时间占比很小;如果代码执行时间很短,则内联函数就可以节省函数调用的时间。

  • 含有递归调用的函数不能设置为inline;
  • 使用了复杂流程控制语句:循环语句和switch语句,不能设置为inline;
  • 由于inline增加体积的特性,所以建议inline函数内的代码应很短小。最好不超过5行;
  • 内联函数应该在头文件中定义,关键字inline 必须与函数定义体放在一起才能使函数成为内联,仅将inline 放在函数声明前面不起任何作用。
C语言三剑客:普通函数、内联函数与函数式宏定义的终极对决 C语言里的函数式宏,堪称「参数接收界的「万能选手」」——它能像普通函数一样「吃」参数,但偏偏「不挑食」也不「验身份」!打个比方,普通函数像「定制餐厅」:你点什么菜(传什么类型参数),厨房就按菜单(函数声明)准备食材(生成对应类型代码)。比如你要「int版max」,厨房就做份「int原料」的max菜;你要「double版」,就得单点一份「double原料」的——这叫「类型检查」,安全但麻烦。 阅读详情

相关推荐

科普:Frenet坐标

理想情况下,描述这种常见驾驶行为在数学上应该很容易。一种方法是使用新的坐标系。现在,而不是放下一个正常的笛卡尔网格,我们做一些事情,就像你看到下面…Frenet Coordinates是一种以比传统x,y笛卡尔坐标更直观的方式表示道路位置的方式。如果我们想要方程式来描述这个动作,那就不容易了!想象一下像下面这样一条弯曲的道路,笛卡尔坐标系就位于它的上面…使用这些笛卡尔坐标,我们可以尝试描述车辆通常在路上行驶的路径…那么在Frenet坐标系下呈现的典型轨迹是什么样的?在这里,我们定义了一个新的坐标系统。

OceanStar的博客 1万+

内联函数和普通函数的区别

1. 内联函数和普通函数的参数传递机制相同,但是编译器会在每处调用内联函数的地方将内联函数内容展开,这样既避免了函数调用的开销又没有宏机制的缺陷 2. 普通函数在被调用的时候,系统首先要到函数的入口地址去执行函数体,执行完成之后再回到函数调用的地方继续执行,函数始终只有一个复制。     内联函数不需要寻址,当执行到内联函数的时候,将此函数展开,如果程序中有N次调用了内联函数则会有N次展开函数...

weixin_41786584的博客 1万+

SAP中成本估算没有找到工艺路线消息处理实例

在针对成品的标准成本核算处理过程中,系统中会经由设定好的策略来收集成品相关成本组成,最终计算出产成品的标准成本。关于成本组成,可以归纳为三个基本要素,料,工,费。即标准成本就是要知道,生产一件成品,需要消耗多少钱的原材料?消耗多少钱的人工?以及其它的间接消耗? 某日,接到CO同事的反馈,在用CK11N做产成品标准价格核算时,提示没有工艺路线确定,但该消息为绿灯,可以通过。基于业务上的谨慎,提出分析。 从提示可以看出问题与工艺路线有关。因为,成品工艺路线中设定有成品生产所耗工时,所以,在计算产成品标准

专注SAP应用技术文章写作,致力于拉近用户与系统间的距离; 6280

内联函数与普通函数有什么区别?如何定义和使用内联函数?

所以C++中我们是不推荐用宏的,因为有内联函数这个特性,即保留了宏的优点,无需调用函数建立栈帧,而且还修复了宏的缺陷,不再需要将内容写得那么复杂,写成日常的函数形式即可,只需要在前面加上一个inline关键字,就可以起到这种效果。内联函数通过 inline 关键字定义,意在减少函数调用的开销,适合用于小型、频繁调用的函数。内联函数可以在类内部定义,或者在类外部进行定义时使用 inline 关键字。通过这种方式,内联函数可以优化性能,特别是在频繁调用的小型函数中,减少不必要的开销。如何定义和使用内联函数呢?

m0_74343664的博客 1470

【AI平台】n8n入门2:第一个工作流,调用本地大模型

n8n是一款开源的,专注于AI工作流构建,支持灵活的自定义与集成。就是可以把大模型和其他工具联合起来,这就厉害了。而且,免费功能又强大,目前很火,来研究一下。

正经教主是个热衷于正经学习分享的教主。 4532

告别手动改图!用Python+PyWin32驱动SolidWorks,实现参数自动化修改(保姆级避坑指南)

本文详细介绍了如何利用Python和PyWin32驱动SolidWorks实现参数自动化修改,提供从环境配置到API连接的工业级解决方案。通过实战案例和避坑指南,帮助工程师高效搭建自动化脚本工作流,显著提升设计效率。

weixin_30614109的博客 744

区别 :内联函数和普通函数的区别

内联函数和普通函数的区别: 1、在编译过程中,内联函数在函数的调用点,把函数代码全部展开,所以没有标准函数的栈帧的开辟和回退。 (如果 调用函数的开销 > 函数执行的开销,那么就建议写为内联函数 ) 调用的开销:函数的栈帧的开辟和回退 执行的开销:函数体内代码执行的开销 2、内联函数只在本文件可见,编译阶段就进行了替换,所以不产生符号,所以一般在头文件中定义,这样就可以在其它文...

life_binary的博客 2117

全国各省份影像下载地址(11级别)

cesium中使用urltemplate加载,leaflet中使用tile加载,具体加载有问题可以给我留言。

资深三维GIS开发 5152

宏定义和内联函数、及内联函数和普通函数的区别

一、宏定义和内联函数的区别 1. 宏定义不是函数,但是使用起来像函数。预处理器用复制宏代码的方式代替函数的调用,省去了函数压栈退栈过程,提高了效率。     内联函数本质上是一个函数,内联函数一般用于函数体的代码比较简单的函数,不能包含复杂的控制语句,while、switch,并且内联函数本身不能直接调用自身。如果内联函数的函数体过大,编译器会自动的把这个内联函数变成普通函数。   2. ...

爱吃_宫爆鸡丁 873

Android 性能之 Game Mode

本文的目的是介绍 AOSP Game Mode 功能。Game Mode 功能的核心是系统服务 GameManagerService,在本文中用 GMS 指代 GameManagerService。在 API 26 之后,应用开发者可以通过将应用的 category 属性设置为 "game",使系统(即 GMS)能够将该应用识别为 "游戏"。GMS 定义了 4 种 game mode,即 1|2|3|4|standard|performance|battery|custom;

专注于系统快稳省领域 3066

【AI产品思路】用户旅程图与用户全生命周期:到底是什么关系?

用户旅程图(User Journey Map)和用户全生命周期(User Lifecycle)是两种不同的分析框架。用户旅程聚焦单次交易体验的完整过程(如浏览→下单→售后),关注触点、情绪和优化点;而用户生命周期则关注用户与平台的长期关系(从认知到流失),着重提升留存和LTV。两者互为补充:生命周期是时间维度的关系框架,旅程图是行为维度的体验路径。电商运营中,旅程优化改善单次体验,生命周期优化解决长期增长问题,二者结合才能实现体验提升与商业效率的双赢。

qq_25438419的博客 218

宏定义、内联函数、普通函数的区别

一、宏定义和内联函数的区别 1. 宏定义不是函数,但是使用起来像函数。预处理器用复制宏代码的方式代替函数的调用,省去了函数压栈退栈过程,提高了效率。     内联函数本质上是一个函数,内联函数一般用于函数体的代码比较简单的函数,不能包含复杂的控制语句,while、switch,并且内联函数本身不能直接调用自身。如果内联函数的函数体过大,编译器会自动的把这个内联函数变成普通函数。

gaosaixing的博客 639

Android16 动态隐藏systemUI右侧音量条

本文介绍了如何屏蔽SystemUI系统音量条并显示自定义音量控制条的实现方法。主要通过两个步骤:1)在编译脚本中定义控制属性persist.rp.show.volume.dialog=off来隐藏系统音量条;2)修改SystemUI源码中的VolumeDialogImpl.java文件,在showH方法中根据属性值判断是否显示系统音量条。当属性值为off时直接return,从而屏蔽系统音量条的显示,实现自定义音量控制条的替代显示。该方法通过系统属性控制显示状态,具有灵活可控的特点。

tzj1058756809的博客 780

C++内联函数、宏定义和普通函数的区别

C++内联函数、宏定义和普通函数的区别? 宏定义:在预处理阶段进行简单的文本替换,不会进行参数类型检查; 内联函数:编译器会在每次调用内联函数的地方直接将内联函数的内容展开,这样可以省去函数压栈和出栈的开销提高效率,会进行参数类型检查; 普通函数:在函数调用时,跳转到函数地址执行代码; 转载于:https://www.cnblogs.com/dingou/p/10549225.html...

weixin_30653097的博客 257

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

c语言函数定义_C语言中的普通函数,内联函数和函数式宏定义,到底有什么区别?...

前几天,有粉丝(@学无止境攻城狮)在我的一篇介绍C语言宏定义的文章的评论区回复说:“希望写一个关于内联函数和普通函数的区别,内联函数和宏函数的区别。”粉丝的问题@学无止境攻城狮提到,对C语言中的内联函数、普通函数以及函数式宏定义的适用场景不够了解,也就是说在C语言程序开发中,“不清楚什么时候用函数式宏定义好,还是用内联函数,或者普通函数好”。可能读者也有这样的疑惑,所以本文讨论这几种“函数”的区别...

weixin_39534121的博客 282

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

c语言里面inline的作用,C语言内联函数(inline),普通函数,和函数式宏定义的区别,与使用场景...

前几天,有粉丝(@学无止境攻城狮)在我的一篇介绍C语言宏定义的文章的评论区回复说:希望写一个关于内联函数和普通函数的区别,内联函数和宏函数的区别。@学无止境攻城狮 提到,对C语言中的内联函数、普通函数以及函数式宏定义的适用场景不够了解,也就是说在C语言程序开发中,“不清楚什么时候用函数式宏定义好,还是用内联函数,或者普通函数好”。可能读者也有这样的疑惑,所以本文讨论这几种“函数”的区别,在了解区别...

weixin_32390279的博客 660

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

[C++基础]宏定义、内联函数、普通函数的区别

转载自:http://blog.youkuaiyun.com/gao675597253/article/details/7397373 用内联取代宏: 1.内联函数在运行时可调试,而宏定义不可以; 2.编译器会对内联函数的参数类型做安全检查或自动类型转换(同普通函数),而宏定义则不会;  3.内联函数可以访问类的成员变量,宏定义则不能;  4.在类中声明同时定义的成员函数,自动转

kaisawind的专栏 731

C++ 内联函数,宏定义函数和普通函数的区别:

这个问题是面试中经常遇到的,再一次华为的面试中面试官就问道我这个问题,当时,答的不是很好,甚至有些错误,特此根据自己的理解,总结一下。本人水平不高,有什么错误,欢迎提出!     首先,我们都知道C++从源代码到执行经过3个大体的步骤: 1.预处理,这个阶段主要是将宏定义的符号在源程序中进行替换,比图#define pi 3.1415,这个时期就是将源程序中的所有的pi这样的符号替换为3.1415...

daydayup_666的博客 994

中的极大值 宏定义_C语言中的普通函数,内联函数和函数式宏定义,到底有什么区别?...

前几天,有粉丝(@学无止境攻城狮)在我的一篇介绍C语言宏定义的文章的评论区回复说:“希望写一个关于内联函数和普通函数的区别,内联函数和宏函数的区别。”粉丝的问题@学无止境攻城狮提到,对C语言中的内联函数、普通函数以及函数式宏定义的适用场景不够了解,也就是说在C语言程序开发中,“不清楚什么时候用函数式宏定义好,还是用内联函数,或者普通函数好”。可能读者也有这样的疑惑,所以本文讨论这几种“函数”的区别...

weixin_35561409的博客 103

宏定义与内联函数的区别与联系

内联函数一般用于函数体的代码比较简单的函数,不能包含复杂的控制语句,while、switch,并且内联函数本身不能直接调用自身。1. 内联函数和普通函数的参数传递机制相同,但是编译器会在每处调用内联函数的地方将内联函数内容展开,这样既避免了函数调用的开销又没有宏机制的缺陷。的时候进行代码插入,编译器会在每处调用内联函数的地方直接把内联函数的内容展开,这样可以省去函数的调用的开销,提高效率;内联函数不需要寻址,当执行到内联函数的时候,将此函数展开,如果程序中有N次调用了内联函数则会有N次展开函数代码。

qq_54178958的博客 924

宏定义和内联函数的区别

一、宏定义和内联函数的区别 1. 宏定义不是函数,但是使用起来像函数。预处理器用复制宏代码的方式代替函数的调用,省去了函数压栈退栈过程,提高了效率。 内联函数本质上是一个函数,内联函数一般用于函数体的代码比较简单的函数,不能包含复杂的控制语句,while、switch,并且内联函数本身不能直接调用自身。如果内联函数的函数体过大,编译器会自动的把这个内联函数变成普通函数。 2. 宏定义...

上道的程序员 6921

内联函数、宏定义和普通函数

二、内联函数的作用 首先我们再viso studio中编写如下代码: int add(int a, int b) { int c = a + b; return c; } int main() { int d; d = add(1,2); printf("d=%d\r\n",d); } 反汇编后得到如下汇编代码: int add(int a, int b) { //入栈保护现场 00B...

weixin_39270987的博客 291

C++中宏定义和内联函数区别

一、宏定义和内联函数的区别 1. 宏定义不是函数,但是使用起来像函数。预处理器用复制宏代码的方式代替函数的调用,省去了函数压栈退栈过程,提高了效率。 内联函数本质上是一个函数,内联函数一般用于函数体的代码比较简单的函数,不能包含复杂的控制语句,while、switch,并且内联函数本身不能直接调用自身。如果内联函数的函数体过大,编译器会自动的把这个内联函数变成普通函数。 2. ...

LANGZI7758521的专栏 498

内联函数、宏和普通函数的区别

1、内联函数和宏的区别 宏定义不是函数,但是使用起来像函数。预处理器用复制宏代码的方式代替函数的调用,省去了函数压栈退栈过程,提高了效率。 内联函数本质上是一个函数,内联函数一般用于函数体的代码比较简单的函数,不能包含复杂的控制语句,while、switch,并且内联函数本身不能直接调用自身。如果内联函数的函数体过大,编译器会自动的把这个内联函数变成普通函数。 宏定义是在预编译的时候把所有的宏...

everthing willl be ok 3502
上一篇: CString,string,char*转换
下一篇: java中的接口与C++的多继承
WJSZMD
博客等级 码龄10年 9粉丝 56原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值