宏函数与函数的区别

本文涉及的产品
云原生网关 MSE Higress,422元/月
可观测监控 Prometheus 版,每月50GB免费额度
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 宏函数和函数都是编程中常用的代码复用方式。宏函数由预处理器处理,在编译前将调用处替换为定义的内容,通常用于简单的文本替换,不进行类型检查;而函数由编译器处理,支持参数传递、返回值和类型检查,更加灵活和安全。
  1. 定义方式

    • 宏函数:是通过预处理器指令#define来定义的。它本质上是一种文本替换机制。例如:
      #define ADD(x,y) ((x)+(y))
      
    • 这个宏函数ADD在预处理阶段,所有出现ADD(a,b)ab为合适的表达式)的地方都会被替换为((a)+(b))
    • 函数:在C和C++等语言中,函数有完整的函数头和函数体。以C语言为例,函数定义形式如下:
      int add(int x, int y) {
             
        return x + y;
      }
      
    • 这里定义了一个名为add的函数,它有明确的参数类型(int型的xy)和返回值类型(int),并且函数体中包含了具体的计算逻辑(返回x + y)。
  2. 执行过程和性能差异

    • 宏函数:在预处理阶段进行文本替换,编译器在编译时会把替换后的代码直接编译。由于没有函数调用的开销,如参数传递、栈帧的建立和销毁等操作,对于简单的宏函数,在执行效率上可能会比函数高。例如,对于一个简单的宏函数#define SQUARE(x) ((x)*(x)),在代码中使用SQUARE(a)时,会直接替换为((a)*(a))进行编译。
    • 函数:在程序执行过程中,当调用函数时,需要进行一系列的操作。首先会将参数压栈,然后程序的执行流程跳转到函数的代码位置,执行函数体中的代码,最后将返回值(如果有)传递回调用处,并进行栈帧的销毁等操作。这些操作会带来一定的性能开销。例如,调用上面定义的add函数时,系统需要完成这些步骤才能得到结果。
  3. 参数类型检查

    • 宏函数:没有严格的参数类型检查。宏函数的参数只是简单的文本替换,所以它可以接受各种类型的参数,只要替换后的表达式在语法上是正确的就行。例如,对于宏函数#define MAX(a,b) ((a) > (b)? (a) : (b))ab可以是intfloat、甚至是自定义的结构体等,只要这些类型支持>比较操作符即可。
    • 函数:有严格的参数类型检查。函数在定义时就确定了参数的类型,在调用函数时,编译器会检查传入的参数类型是否与函数定义的参数类型匹配。如果不匹配,编译器会报错。例如,在C语言中,如果定义了int add(int x, int y)函数,而调用时传入add(3.5, 2.5)(两个float型参数),编译器会发出类型不匹配的警告或错误。
  4. 作用域和生命周期

    • 宏函数:没有像函数那样的局部作用域和生命周期的概念。宏函数在预处理阶段进行文本替换后,就和它替换后的代码的作用域和生命周期相同。因为它不是真正的函数,不存在像函数内部变量的作用域等问题。例如,在一个if - else语句块中定义的宏函数和在函数外部定义的宏函数在替换后的代码作用域上没有本质区别。
    • 函数:函数有自己的局部作用域。函数内部定义的变量在函数执行结束后就会被销毁(生命周期结束)。例如,在函数int add(int x, int y)中定义的局部变量,其作用域仅限于函数体内部,当函数返回后这些变量就不存在了。
  5. 代码调试难度

    • 宏函数:调试相对困难。因为宏函数是在预处理阶段进行替换,当出现错误时,编译器给出的错误信息通常是针对替换后的代码,而不是宏函数本身的定义。这使得定位错误的源头比较麻烦。例如,如果宏函数替换后的表达式语法错误,编译器会指出错误在替换后的那一行代码,很难直接关联到宏函数的定义。
    • 函数:调试相对容易。函数有明确的调用栈和局部变量等信息,调试器可以很方便地跟踪函数的执行过程,查看函数内部变量的值,以及函数调用的参数传递情况等。这有助于快速定位和解决代码中的错误。
相关文章
|
存储 JSON 数据格式
UCB Data100:数据科学的原理和技巧:第一章到第五章
UCB Data100:数据科学的原理和技巧:第一章到第五章
465 0
UCB Data100:数据科学的原理和技巧:第一章到第五章
软著 | 新版软著申请教程(软著已拿到)
次申请软著是三年前的2020年了,那个时候还是纸质版本的软著申请,需要现在打印材料,然后寄到北京去,后面发现改版了,改成了电子材料上传即可,所以就有了这期教程啦!希望可以帮助到正在申请软著头疼的朋友们!今天刚刚才看到,我的软著申请下来了,还是电子版本的!
1596 1
软著 | 新版软著申请教程(软著已拿到)
xxl-job执行器启动报错读取不到配置文件Could not resolve placeholder ‘xxl.job.executor.address‘ in value “${xxl.job
有几个不用配置的属性,也要写出来,不填值就行 但是最后一个日志天数得写,写个-1。不然空字符串无法转成数字
|
11月前
|
算法 编译器 C语言
宏函数以及作用
宏函数是在预处理阶段由编译器进行替换的代码片段,常用于常量定义、简单计算和代码简化。它们以 `#define` 开头,不进行类型检查,使用时需谨慎。
|
8月前
|
存储 弹性计算 人工智能
2025年阿里云企业云服务器ECS选购与配置全攻略
本文介绍了阿里云服务器的核心配置选择方法论,涵盖算力需求分析、网络与存储设计、地域部署策略三大维度。针对不同业务场景,如初创企业官网和AI模型训练平台,提供了具体配置方案。同时,详细讲解了购买操作指南及长期运维优化建议,帮助用户快速实现业务上云并确保高效运行。访问阿里云官方资源聚合平台可获取更多最新产品动态和技术支持。
|
11月前
|
存储 安全 Java
如何避免 Java 中的“ArrayStoreException”异常
在Java中,ArrayStoreException异常通常发生在尝试将不兼容的对象存储到泛型数组中时。为了避免这种异常,确保在操作数组时遵循以下几点:1. 使用泛型确保类型安全;2. 避免生类型(raw types)的使用;3. 在添加元素前进行类型检查。通过这些方法,可以有效防止 ArrayStoreException 的发生。
182 3
|
10月前
|
编解码 前端开发 搜索推荐
如何建立自己的体育直播平台-源码搭建全流程
随着在线观看体育赛事用户的爆发式增长,搭建专业体育直播应用成为趋势。利用如熊猫比分的全链路解决方案,创业者可快速启动平台。主要步骤包括前期技术准备(赛事API接口、服务器配置、域名选择、短信服务、云直播服务)、定制化(LOGO标识、功能测试与优化)及正式上线与运营(推广、持续更新、主播入驻)。此方案使创业者能高效进入体育市场,抓住机遇。
|
JavaScript Linux iOS开发
【Mac系统】Vscode使用LeetCode插件报错‘leetcode.toggleLeetCodeCn‘ not found
在Mac系统下使用VSCode的LeetCode插件时遇到“leetcode.toggleleetcodecn”命令找不到的错误解决方法,主要是通过从Nodejs官网下载并安装最新版本的Node.js来解决环境配置问题。
683 0
HDLC与PPP的区别
【4月更文挑战第11天】
497 0
HDLC与PPP的区别
|
存储 算法 Java
【DFS(深度优先搜索)详解】看这一篇就够啦
本文介绍了深度优先搜索(DFS)算法及其应用。DFS从某个顶点出发,深入探索图的每条路径,直到无法前进为止,然后回溯。文章详细解释了DFS的基本思想,并通过示例图展示了其执行过程。此外,文中还探讨了三种枚举方式:指数型枚举、排列型枚举和组合型枚举,并提供了具体的代码实现。最后,文章通过几道练习题帮助读者更好地理解和应用DFS算法。
9098 19
【DFS(深度优先搜索)详解】看这一篇就够啦