多行宏须用反斜杠续行且末尾不能有空格;多语句宏需用do{...}while(0)包裹;宏参数和整体表达式必须加括号防优先级错误;#和##运算符不可跨行使用。

多行宏必须用反斜杠 \ 续行,且每行末尾都要加
编译器在预处理阶段看到 #define 后,会把整块宏体当作一行文本处理;如果换行不加 \,就等于提前结束了宏定义,后续内容会被当成普通代码或语法错误。常见错误是漏掉某一行末尾的 \,导致编译报错如 expected identifier or '(' before 'if' 或直接跳过后面几行。
必须注意:
-
\后不能有任何字符(包括空格、tab、注释),否则续行失效 - 最后一行宏体末尾 不能 加
\ - 宏体内换行只影响可读性,不影响生成逻辑——它仍是纯文本替换
多语句宏要用 do { ... } while(0) 包裹
直接写多条语句(如 printf + fflush)看似可行,但一旦用在 if 无花括号分支里,就会出问题。例如:
#define LOG(msg) printf("[LOG] %s\n", msg); fflush(stdout)
if (debug) LOG("start"); else LOG("skip");
实际展开后变成:
if (debug) printf("[LOG] %s\n", msg); fflush(stdout); else LOG("skip");
因为 fflush(stdout); 不在 if 范围内,else 就悬空报错。
正确做法是用 do { ... } while(0) 把多条语句包成一个逻辑单元:
#define LOG(msg) do { \
printf("[LOG] %s\n", msg); \
fflush(stdout); \
} while(0)
这样无论上下文如何,宏调用都等价于一条“语句”,能安全用于 if、for 等控制结构中。
宏参数和表达式必须加括号,否则运算优先级会崩
比如写 #define MAX(a,b) a > b ? a : b,调用 MAX(x + 1, y * 2) 展开后是 x + 1 > y * 2 ? x + 1 : y * 2,看起来没问题;但若写成 MAX(x++, y++),就会变成 x++ > y++ ? x++ : y++,导致副作用被多次触发。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
更隐蔽的问题来自宏参数参与算术运算时的优先级,例如:
#define SQUARE(x) x * x int z = 2 * SQUARE(1 + 2); // 展开为 2 * 1 + 2 * 1 + 2 → 结果是 6,不是 18
所以必须对每个参数和整个宏体加括号:
#define SQUARE(x) ((x) * (x))
同理,所有带参宏中的参数出现处,都应套上 (x),避免被外部运算符“撕开”。
字符串化和拼接操作(# 和 ##)不能跨行使用
#(字符串化)和 ##(标记连接)是预处理器运算符,它们只在单行宏体内生效。如果你试图把 #param 拆到两行写,或者把 a##b 中间换行,预处理器会直接报错 invalid preprocessing token 或 pasting "a" and "\n" does not give a valid preprocessing token。
这类操作必须保持紧凑:
#define STR(x) #x #define CONCAT(a, b) a##b // ✅ 正确 STR(hello) // → "hello" CONCAT(var, 1) // → var1 <p>// ❌ 错误(不能跨行)</p><h1>define BAD_STR(x) # \</h1><p>x </p>
跨行只适用于普通文本拼接,不适用于预处理运算符本身——这是最容易忽略的边界限制。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










