C 宏函数

宏函数(带参宏)

#define ADD(A,B) ((A)+(B))

✅ 要点:

● 无类型,不做类型检查

● 参数 A、B 各自加括号,整体表达式也要套括号,防止运算符优先级灾难

● 末尾不能加分号,加分号会把;一并替换进代码

普通函数 vs 宏函数

对比项 普通函数 Add(int a, int b) 宏函数 ADD(A,B)
处理时机 编译阶段,生成独立函数,调用时 call 跳转 预处理阶段文本替换,没有函数实体
调用开销 参数传递、call/ret、栈操作,有开销 无函数调用开销,直接原地展开代码
类型检查 有,参数类型不匹配直接报错 无,随便传,编译不报错,容易出诡异 bug
返回值 有固定返回类型 只是文本替换,没有返回值概念
调试 可以断点进入函数内部 不能断点,宏展开后不存在这个 "函数"

错误示范(不加括号)

c 复制代码
#define BAD_ADD(A,B) A+B
// 调用:BAD_ADD(1,2)*10
// 替换后:1+2*10 → 结果21,预期30,优先级出错
c 复制代码
#define BAD_ADD(A,B) (A+B)
// 调用:BAD_ADD(1||2,3) ? 1 :0 ,缺少外层括号也会出问题

宏函数典型坑点

坑 1:参数带自增 / 自减

c 复制代码
#define ADD(A,B) ((A)+(B))
int a=1;
int res = ADD(a++, a);
// 展开:((a++) + (a)),a++会执行两次,结果不符合预期

宏只是文本替换,参数如果带有副作用(++、--、函数调用),会多次执行!普通函数不会

坑 2:末尾加分号

c 复制代码
#define ADD(A,B) ((A)+(B));
int r = ADD(1,2);
//替换后 int r = ((1)+(2)); ;  多一个空语句,部分场景语法报错

坑 3:无类型检查

c 复制代码
ADD("123",123);

不会报错,直接计算字符串字面量地址 + 123,得到一个无意义数字

什么时候用宏函数,什么时候用普通函数

✅ 适合宏:极简短运算,求最大最小值、简单位运算,追求极小开销

❌ 不要宏:代码逻辑复杂、参数有 ++ 这类副作用、需要断点调试、需要类型安全 → 用内联函数inline

补充:inline 内联函数(用来替代宏函数)

C99 引入,兼顾两者优点:

  1. 有类型检查
  2. 编译器原地展开,没有 call 调用开销
  3. 可以断点调试
c 复制代码
inline int Add(int a,int b)
{
    return a+b;
}
相关推荐
白杨尚青2 分钟前
C++进阶篇(六):map 和 set 的模拟实现——用红黑树封装 mymap/myset(迭代器 + operator[])
开发语言·c++·迭代器·stl·set·map·红黑树
饮水桶_T4 小时前
JAVA IO流笔记
开发语言·数据结构·算法
Felven6 小时前
C. Brr Brrr Patapim
c语言·开发语言
路溪非溪7 小时前
python标准库使用总结
开发语言·python
Zwawa8 小时前
嵌入式OLED表驱动菜单:用一张表、一个栈和一个窗口重写表驱动菜单
c语言·单片机·嵌入式
SomeOtherTime9 小时前
Rust 面向对象介绍(AI回答)
开发语言·python·rust
zh_xuan9 小时前
kotlin常见面试题
开发语言·kotlin·面试题
草莓熊Lotso11 小时前
【C++ 基于微服务的即时通讯系统】文件存储子服务实战:UUID生成、文件IO封装与全接口单元测试
开发语言·网络·数据库·c++·微服务·架构·单元测试
huaqianzkh12 小时前
WinForm C#:循环修改控件UI闪烁卡顿?SuspendLayout / ResumeLayout 与 BeginUpdate 优化
开发语言·ui·c#
沐晓时光1 天前
C语言入门,内存函数知识讲解
c语言·开发语言