建站优化,网站建设企业排行,甘肃建设体网站首页,学校网站下载作者#xff1a;☆星轨★ 链接#xff1a;https://blog.csdn.net/qq_35692077/article/details/1029949591. 函数宏介绍函数宏#xff0c;即包含多条语句的宏定义#xff0c;其通常为某一被频繁调用的功能的语句封装#xff0c;且不想通过函数方式封装来降低额外的弹栈压… 作者☆星轨★ 链接https://blog.csdn.net/qq_35692077/article/details/1029949591. 函数宏介绍函数宏即包含多条语句的宏定义其通常为某一被频繁调用的功能的语句封装且不想通过函数方式封装来降低额外的弹栈压栈开销。函数宏本质上为宏可以直接进行定义例如#define INT_SWAP(a,b) \int tmp a; \a b; \b tmp
但上述的宏具有一个明显的缺点当遇到 if、while 等语句且不使用花括号仅调用宏时实际作用范围在宏的第一个分号后便结束。即 a b 和 b tmp 均不受控制语句所作用。因此在工程中一般使用三种方式来对函数宏进行封装分别为 {}、do{...}while(0) 和 ({})。下文将一一对三种方式进行分析比较各自的优劣点。2. {} 方式INT_SWAP 宏使用 {} 封装后形态如下#define INT_SWAP(a,b)\
{ \int tmp a; \a b; \b tmp; \
}
此时直接调用与在无花括号的控制语句如 if、while中调用均能正常运行例如#define INT_SWAP(a,b) \
{ \int tmp a; \a b; \b tmp; \
}int main()
{int var_a 1;int var_b 2;INT_SWAP(var_a, var_b);printf(var_a %d, var_b %d\n, var_a, var_b); // var_a 2, var_b 1if (1)INT_SWAP(var_a, var_b);printf(var_a %d, var_b %d\n, var_a, var_b); // var_a 1, var_b 2
}
但当无花括号的 if 语句存在其他分支else if、else 等如if (1)INT_SWAP(var_a, var_b);
elseprintf(hello world!\n);
会发现编译出错...
/mnt/hgfs/share/pr_c/src/main.c: In function ‘main’:
/mnt/hgfs/share/pr_c/src/main.c:18:2: error: ‘else’ without a previous ‘if’else
这是因为 INT_SWAP(var_a, var_b); 最后的 ; 已经把 if 的作用域终结了后续的 else 当然没有找到与之匹配的 if 了。因此解决方法有两种分别为不使用 ;port.1或规定必须使用带花括号的 ifport.2例如/* port.1 */
if (1)INT_SWAP(var_a, var_b)
else
{printf(hello world!\n);
}/* port.2 */
if (1)
{INT_SWAP(var_a, var_b);
}
else
{printf(hello world!\n);
}
可见不使用 ; 的调用方式无论从程序阅读还是使用方法方面都是十分别扭的而规定必须使用带花括号的 if 的调用方式有违常理的因为宏函数应该适用于任何语法。优缺点总结优点简单粗暴。缺点不能在无花括号且有分支的 if 语句中直接调用能够不带 ; 直接调用。3. do{...}while(0) 方式INT_SWAP 宏使用 do{...}while(0) 封装后形态如下#define INT_SWAP(a,b) \
do{ \int tmp a; \a b; \b tmp; \
}while(0)
do{...}while(0) 表示只执行一遍 {} 内的语句表象来说与 {} 的功能是一致的。不同的是do{...}while(0) 可以提前退出函数宏、整合为一条语句与强制调用时必须使用 ;。由于 do{...}while(0) 实际为 while 循环因此可以使用关键字 break 提前结束循环。利用该特性可以为函数宏添加参数检测。例如#define INT_SWAP(a,b) \
do{ \if (a 0 || b 0) \break; \int tmp a; \a b; \b tmp; \
}while(0)
由于 do{...}while(0); 实际为一种语法编译器会把 do{...}while(0); 认为为一条语句。因此do{...}while(0) 方式的函数宏可以在无花括号且有分支的 if 语句中直接调用。例如#define INT_SWAP(a,b) \
do{ \if (a 0 || b 0) \break; \int tmp a; \a b; \b tmp; \
}while(0)int main()
{int var_a 1;int var_b 2;if (1)INT_SWAP(var_a, var_b);elseprintf(hello world!\n); printf(var_a %d, var_b %d\n, var_a, var_b); // var_a 2, var_b 1return 0;
}C 语言规定do{...}while(0) 语法必须使用 ; 作为语句结尾。因此不可能存在以下语句的程序出现if (1)INT_SWAP(var_a, var_b)
else
{printf(hello world!\n);
}优缺点总结优点支持在无花括号且有分支的 if 语句中直接调用支持提前退出函数宏强制调用时必须使用 ;。缺点无返回值不能作为表达式的右值使用。4. ({}) 方式({}) 为 GNU C 扩展的语法非 C 语言的原生语法。INT_SWAP 宏使用 ({}) 封装后形态如下#define INT_SWAP(a,b) \
({ \int tmp a; \a b; \b tmp; \
})与 do{...}while(0) 相同({}) 支持在无花括号且有分支的 if 语句中直接调用。例如#define INT_SWAP(a,b) \
({ \int tmp a; \a b; \b tmp; \
})int main()
{int var_a 1;int var_b 2;if (1)INT_SWAP(var_a, var_b);elseprintf(hello world!\n);printf(var_a %d, var_b %d\n, var_a, var_b); // var_a 2, var_b 1return 0;
}与 do{...}while(0) 不同的是({}) 不能提前退出函数宏与支持返回值。({}) 毕竟不是 while 循环不能直接使用 break退出函数宏是比较容易理解。那支持返回值是什么意思呢答案是 C 语言规定 ({}) 中的最后一条语句的结果为该双括号体的返回值。例如int main()
{int a ({10;1000;});printf(a %d\n, a); // a 1000
}因此({}) 可以为函数宏提供返回值。例如#define INT_SWAP(a,b) \
({ \int ret 0; \if (a 0 || b 0) \{ \ret -1; \} \else \{ \int tmp a; \a b; \b tmp; \} \ret; \
})int main()
{int var_a 1;int var_b 2;if (INT_SWAP(var_a, var_b) ! -1)printf(swap success !!\n); // swap success !!elseprintf(swap fail !!\n); printf(var_a %d, var_b %d\n, var_a, var_b); // var_a 2, var_b 1return 0;
}
可见此时的 INT_SWAP 宏已与函数十分接近。优缺点总结优点支持在无花括号且有分支的 if 语句中直接调用有返回值支持作为表达式的右值。缺点不支持提前退出函数宏非 C 的原生语法编译器可能不支持。5. 总结综上在 {}、do{...}while(0) 和 ({}) 这三种函数宏的封装方式之中应尽可能不使用 {}考虑兼容性一般选择使用 do{...}while(0)当需要函数宏返回时可以考虑使用 ({}) 或直接定义函数。免责声明本文来源网络免费传达知识版权归原作者所有。如涉及作品版权问题请联系我进行删除。推荐阅读专辑|Linux文章汇总专辑|程序人生专辑|C语言我的知识小密圈