C 语言函数宏的单行与多行封装

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

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

一、宏函数的单行写法

比如:

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

二、宏函数的多行写法

前面我们介绍的宏函数是单行定义的,那么假设我们的宏函数有多行应该怎么写呢?写法和实际写函数的时候有一点区别,换行的时候需要加反斜杠"\"分隔,总共有3种方式

{}单大括号方式

比如:

#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)或者 if(1){}流控制块方式 

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

注意:宏中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的原生语法(GCC支持的statement expression语法,用于将多条语句打包成一个表达式),编译器可能不支持。

附:以下使用 ({ }) 方法为一个改写 平方和 函数的案例:

// 原函数定义
int add(int x, int y) {
    return x*x + y*y;
}
// 宏定义
#define ADD(x, y) ({ \
    int _x = (x); \
    int _y = (y); \
    _x*_x + _y*_y; \
})
// 使用示例
int main() {
    int a = 3, b = 4;
    int c = add(a, b);
    int d = ADD(a, b);
    printf("%d %d\n", c, d); // 输出:25 25
    return 0;
}

注:宏定义不需要函数的返回值类型,因此需要确定函数的返回值类型并将其包含在宏定义中。

 

④、总结

综上,在{}、do{...}while(0)和({})这三种函数宏的封装方式之中,应:

  • 尽可能不使用{}单大括号模式,
  • 考虑兼容性一般选择使用 do{...}while(0)流控制语句块模式,
  • 当需要函数宏返回时可以考虑使用({})小括号+大括号模式,或直接定义函数

 

参考资料:

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

posted @ 2024-05-26 11:28  FBshark  阅读(97)  评论(0编辑  收藏  举报