宏定义无类型和作用域,仅文本替换;常见错误包括括号缺失、分号误加、空格干扰及多语句未用do-while(0)封装,导致优先级错乱、语法错误或else悬空等问题。

宏定义没有“类型”或“作用域”,只有文本替换规则;写错括号、分号或空格,编译器不会报错,但行为可能完全偏离预期。
无参宏的写法和常见翻车点
无参宏本质是纯文本替换,例如 #define PI 3.14159,所有出现 PI 的地方都会被原样替换成 3.14159。
- 宏名后不能有空格再跟括号,
#define MAX_SIZE (1024)是合法的,但#define MAX_SIZE () 1024会让MAX_SIZE()被展开成() 1024,直接语法错误 - 末尾绝不能加分号,
#define DEBUG_LOG printf("debug\n");看似顺眼,但用在if (x) DEBUG_LOG里会变成if (x) printf("debug\n");;,多出的分号让 else 无法匹配 - 如果宏体含表达式(比如
#define BUFFER_LEN 256 + 16),用在int buf[BUFFER_LEN * 2]中会扩展为int buf[256 + 16 * 2],结果是 288 而非预期的 544 —— 必须写成#define BUFFER_LEN (256 + 16)
带参宏必须加括号包裹每个参数和整个表达式
带参宏不是函数,不求值、不检查类型,只做字符串拼接。典型错误是 #define SQUARE(x) x * x,调用 SQUARE(a + b) 展开为 a + b * a + b,优先级崩坏。
- 正确写法是
#define SQUARE(x) ((x) * (x)):外层括号保整体,内层括号保每个参数 - 像
#define MAX(a, b) (a) > (b) ? (a) : (b)这种写法仍有隐患——若用于int z = MAX(x, y) + 1;,会展开为(x) > (y) ? (x) : (y) + 1,+1 只作用于 else 分支。必须写成#define MAX(a, b) ((a) > (b) ? (a) : (b)) - 宏名与左括号之间不能有空格,
#define MAX (a, b) ...会被当作无参宏,把整个(a, b) ...当作替换文本
多语句宏要用 do while(0) 封装
想让宏支持分号结尾、能放在 if/else 里安全执行,比如日志+计数,不能写成裸花括号块:{ printf(...); ++count; },否则 if (x) LOG_AND_INC(); else ... 会因 else 悬空报错。
立即学习“C++免费学习笔记(深入)”;
- 必须用
do { ... } while(0)包裹,它语法上是一个完整语句,支持后面跟分号,且能正确参与 if/else 配对 - 不要用
if (1) { ... }或for(;;) { ... break; }替代 —— 前者在某些旧编译器下可能警告,后者语义冗余且易被误读 - 这种封装不改变执行逻辑,也不引入运行时开销,纯粹解决语法歧义
宏的危险不在“不会用”,而在“看起来能用”。哪怕一个 #define 看起来只是换了个名字,只要它参与了运算、分支或声明上下文,括号、空格、分号这三处就极大概率埋着雷。调试时看不到宏展开后的实际代码,问题往往要到运行时才暴露。


















