跳转至

知识点 08 · 预处理与宏

本页最后更新于 ,内容可能过时

说明 · 预处理指令与宏的三条黄金法则

预处理(# 开头)发生在编译之前,做的是纯文本层面的事:

指令 作用
#include stdio.h 等头文件内容原样插进来
#define / #undef 宏定义 / 取消宏定义(宏展开 = 文本替换)
#if #ifdef #ifndef #else #endif 条件编译:按条件决定哪段代码参与编译(#ifndef X#endif 就是"头文件卫士"的写法)

宏是"文本替换",不是函数调用! 宏的参数在展开时直接原样代入,不会自动加括号。

宏的三条黄金法则

  1. 每个参数都加括号:((x) * (x)) 而不是 x * x
  2. 整个表达式再加一层括号:(x + 1) 而不是 x + 1
  3. 能不用宏就不用,优先 static inline 函数或 const 常量。

原因:宏没有类型检查;参数会被求值多次(SQUARE(i++) 会让 i 自增两次);

static inline 函数有类型检查、参数只求值一次,且同样没有函数调用开销。


1 · 宏展开陷阱 · 函数式宏必须加括号

以下程序的运行结果是?

#define SQUARE(x) x * x

int result = SQUARE(2 + 3);
printf("%d\n", result);
  • A. 25
  • B. 13
  • C. 9
  • D. 11
答案

D(11)

解析

宏展开是纯文本替换:

SQUARE(2 + 3)    2 + 3 * 2 + 3

按优先级算:2 + (3*2) + 3 = 2 + 6 + 3 = 11。✅(如果它是函数,答案才会是 25。)

正确写法必须给参数和整体都加括号:

#define SQUARE(x) ((x) * (x))     // → (2+3) * (2+3) = 25

为什么"两层括号"缺一不可?(这是本题的评分点)

写法 SQUARE(2+3) 结果 够不够用
#define M(x) x*x 2+3*2+3 11 ❌
#define M(x) (x)*(x) (2+3)*(2+3) 25 ✅ 本题够用,但换个场景仍翻车:100/M(10)100/(10)*(10) = 100,而不是 1
#define M(x) ((x)*(x)) ((2+3)*(2+3)) 25 ✅ 永远安全
  • 参数加括号:防止 2+3 被乘法的优先级"劈开"(本题就是死在这里)。
  • 整体加括号:防止宏的结果被外层运算符抢走优先级(如上面 100/M(10) 的例子)。
  • 2 + 3 * 2 + 3 的读法:*+ 优先级高,所以先算 3*2,再从左到右加:2+6+3 = 11

易错:选 A)25 —— 那是把它当函数算的结果(材料上只给出 D 与展开式,其余选项未逐项解释)。

宏没有类型、没有优先级保护,参数和整体都要加括号,两层一层都不能少。


2 · 宏展开陷阱(第二道)· 展开后完全按运算符优先级走

以下宏的输出结果是?

#define ADD(x, y) x + y

printf("%d\n", ADD(3, 4) * 2);
  • A. 14
  • B. 11
  • C. 18
  • D. 7
答案

B(11)

解析

这是同一个考点的第二道,只是陷阱从"参数被劈开"(SQUARE(2+3)2+3*2+3)换成了"宏的尾巴被外面的运算符抢走":

ADD(3, 4) * 2    3 + 4 * 2

宏是纯文本替换,展开后的表达式按 C 语言自己的运算符优先级走:*+ 高,所以先算 4 * 2 = 8,再算 3 + 8 = 11。✅

选项对照:

  • A)14 —— 把宏当成函数算的结果:(3+4)*2 = 14。这是最诱人的错误答案。
  • B)11 —— 正确答案:3 + 4*2 = 11
  • C. 18、D)7 —— 其余干扰项(材料上只给出了 B 与展开式,未逐项解释)。

正确写法:整体加括号即可(本题参数本身就是单个数字,参数括号可省,但仍建议都写全):

#define ADD(x, y) ((x) + (y))     // → ((3) + (4)) * 2 = 14

写错时反而看不出问题

改对之后答案就从 11 变成 14 了——宏写错时,结果可能"看起来很正常",这是它最坑的地方。

宏展开后没人替你"兜底",一切按优先级走,所以参数要括号、整体更要括号。

两题对照记忆:

  • #define SQUARE(x) x*x —— 参数 2+3 被劈开(2+3*2+3);
  • #define ADD(x,y) x+y —— 整个宏 被外面的 *2 咬住(3+4*2)。

一个是"参数不加括号",一个是"整体不加括号",正好是黄金法则的前两条各踩一次。