首页 > 其他分享 >c语言函数宏的封装方式有哪几种?

c语言函数宏的封装方式有哪几种?

时间:2024-05-26 11:33:52浏览次数:22  
标签:语句 do 封装 函数 while 哪几种 SWAP

在c语言开发中,出了使用函数封装代码之外,也经常使用宏来封装一些重要或简洁的代码。

宏在c开发有三种:预定义宏,不带参宏,和带参数宏。通常,带参数宏也叫函数宏,函数宏,即包含多条语句的宏定义,其通常为某一被频繁调用的功能的语句封装,且不想通过函数方式封装来降低额外的弹栈压栈开销,在实际项目开发中,函数宏的作用很强大,下面介绍三种常用的三种封装方式:

第一种:{}方式

比如:

#define SWAP(a,b) \
{ \
   a=a+b;\
   b=a-b;\
   a=a-b;\
}

此时如果在非控制语句中调用,则可以正常编译通过,如下:

int main()
{
    int x = 1;
    int y = 2;
    
    SWAP(x, y);
    printf("x=%d, y=%d", x, y);//结果应该是 x=2, y=1
}

但当在控制语句中调用时,比如分支语句if(elseif、else等)如:

if(true)
    SWAP(x,y);
else
{
    printf("hello world\n");
}

编译器会报错,如下:

 上面的语句展开为:

SWAP(x,y);后面的;使得if的作用域终结了,后续的else当然没有找到与之

匹配的if了。宏函数应该适用于任何语法。

这种函数宏的优缺点:

  • 优点:简单粗暴。
  • 缺点:不能在无花括号且有分支的if语句中直接调用;(但能够不带;直接调用)

第二种do{...}while(0)方式

注意:宏中while(0)后没有

#define SWAP(a,b) \
do{ \
   a=a+b;\
   b=a-b;\
   a=a-b;\
}while(0)

另外,do{...}while(0)为控制流语句,是一条复合语句,在语句块中可以添加参数检测。

例如:

#define SWAP(a,b) \
do{ \
   if(a<0 || b<0) break;\
   a=a+b;\
   b=a-b;\
   a=a-b;\
}while(0)

 

编译器会把do{...}while(0);认为为一条语句。因此,do{...}while(0)方式

的函数宏可以在无花括号且有分支的if语句中直接调用。例如:

这种函数宏的优缺点:

  • 优点:支持在无花括号且有分支的if语句中直接调用;支持提前退出函数宏(如参数检查);强制调用时必须使用;。
  • 缺点:无返回值,不能作为表达式的右值使用。

第三种({})方式

({})为GNUC扩展的语法,非C语言的原生语法,封装后形态如下:

#define SWAP(a,b) \
({ \
   a=a+b;\
   b=a-b;\
   a=a-b;\
})

({})既可以用于分支语句中,也可以作为右值,例如:

这种函数宏的优缺点:

优点:支持在无花括号且有分支的if语句中直接调用;有返回值,支持作为表达式的右值。

缺点:不支持提前退出函数宏;非C的原生语法,编译器可能不支持。

总结

综上,在{}、do{...}while(0)和({})这三种函数宏的封装方式之中,应尽可能不使用{},考虑兼容性一般选择使用do{...}while(0),当需要函数宏返回时可以考虑使用({})或直接定义函数。

 

 

参考资料:

1. 《c语言函数宏的封装方式有哪几种?》:https://zhuanlan.zhihu.com/p/666071306

标签:语句,do,封装,函数,while,哪几种,SWAP
From: https://www.cnblogs.com/FBsharl/p/18213464

相关文章

  • Vue3实战笔记(45)—VUE3封装一些echarts常用的组件,附源码
    文章目录前言一、柱状图框选二、折线图堆叠总结前言日前使用hooks的方式封装组件,在我使用复杂的图标时候遇到了些问题,预想在onMounted中初始化echarts,在使用hooks的时候,组件没有渲染完,使用实例会出现各种各样的问题,并且在hooks中使用一些外部属性也属实遇到了些麻烦......
  • MySQL报错注入之Xpath报错&floor函数报错
    目录前言Xpath报错注入updatexml()函数extractvalue()函数floor函数报错count与groupby的虚拟表总结前言报错注入的使用场景一般是页面无法正常回显数据库查询的内容,但是会详细显示查询过程的错误信息。如果连错误信息都没有,那就是盲注了。报错注入的原理就是将子查询语句查询......
  • C++ STL 函数对象:隐藏的陷阱,如何避免状态带来的麻烦?
    STL函数对象:无状态即无压力一、简介二、函数对象三、避免在函数对象中保存状态3.1、函数对象3.2、lambda表达式四、选择合适的更高层次的结构五、总结一、简介在使用C++标准模板库(STL)时,函数对象(FunctionObject)是一种强大的工具,它可以帮助你编写更具表......
  • MySQL函数
    MySQL数据库提供了很多函数包括:数学函数;字符串函数;日期和时间函数;条件判断函数;系统信息函数;加密函数;格式化函数;mysql高级教程:http://cainiao.guashuw.com/一、数学函数数学函数主要用于处理数字,包括整型、浮点数等。函数作用ABS(x)返回x的绝对值......
  • JavaSE的方法 (函数)
    目录Java中的方法(函数)方法声明格式:(与函数类似)Java中的方法(函数)Java方法是一段可重复使用的代码块,用于执行特定的任务。方法可以接受输入参数并返回一个值。在Java中,方法由方法名、参数列表、返回类型、方法体组成。方法声明格式:(与函数类似)[访问权限修饰符修饰符.........
  • React后台管理(九)-- 页面开发前准备---Outlet布局组件封装
    文章目录前言一、组件源码+解析如下二、页面使用方式三、效果展示总结前言本文主要讲Outlet子路由渲染区域—>结构布局的封装。其中涉及的全局搜索hook函数,后面会单独拎出来讲,这期可先忽略,关注布局即可。一、组件源码+解析如下//@/layout/list/index.jsximport......
  • 欧拉函数(新)
    欧拉函数\(\varphi\)的定义,\(\varphi(i)\)表示从\([1,i]\)之间和\(i\)互质的数的数量(\(a\)和\(b\)互质即\(\gcd(a,b)=1\))。欧拉函数是积性函数,例如\(a,b\)都为质数,那么\(φ(ab)=φ(a)\timesφ(b)\),递推式为\[φ(ab)=\frac{φ(a)\timesφ(b)\times......
  • Java SE入门及基础(54)& 函数式接口
    目录1.什么是函数式接口函数式接口示例示例2.函数式编程示例3.Lambda表达式延迟执行应用场景示例4.Consumer接口解释说明示例5.BiConsumer接口解释说明示例6.Predicate接口解释说明示例练习7.Function接口解释说明示例练习1.什么是函数......
  • Vue3实战笔记(43)—Vue3组合式API下封装可复用ECharts图表组件
    文章目录前言一、封装echart图标钩子二、使用步骤总结前言接上文,已经安装好了ECharts,开始封装组件方便使用。一、封装echart图标钩子首先应用我们之前学习的钩子方式,在hooks目录下创建一个名为useECharts.js的文件,用于封装ECharts的逻辑:import{ref,onMo......
  • Lambda表达式的使用以及函数式接口
    目录Lambda表达式1.什么是Lambda表达式2.Lambda表达式的使用3.Lambda表达式的写法规则(以以上例子来说)4.要注意的要点方法引用 函数式接口1.什么是函数式接口2.函数是接口的自定义使用3.JDK自带的函数式接口总结 Lambda表达式1.什么是Lambda表达式Lambda表达......