6月1日 14:53

C语言预处理器指令有哪些?#define 宏有什么坑?

C 预处理器在编译前处理源代码,处理 #include#define#ifdef 等指令。它做的是文本替换,不是代码编译——这意味着宏没有类型检查、没有作用域,出错了很难调试。

追问

#define 宏有什么坑?

经典陷阱:#define SQUARE(x) x * x,调用 SQUARE(1+2) 展开成 1+2 * 1+2,结果是 5 不是 9。正确写法要给参数和整体都加括号:#define SQUARE(x) ((x) * (x))。但即使这样,SQUARE(i++) 还是会让 i 自增两次——宏是文本替换,不是函数调用。能用 inline 函数就别用宏。

#include 尖括号和双引号有什么区别?

<header.h> 在系统目录和编译器指定路径中搜索,"header.h" 先在当前文件所在目录搜索,找不到再到系统目录。所以系统头文件用 <>,自己的头文件用 ""。这只是搜索顺序的区别,不是语法限制——用 #include <myheader.h> 也行,只是可能找不到。

条件编译有哪些常见用法?

三种最常用的模式:1) 跨平台适配(#ifdef _WIN32 ... #else ... #endif);2) 调试开关(#ifdef DEBUG ... #endif,release 编译时整块代码不进去);3) 头文件防重复包含(#ifndef MYHEADER_H ... #define MYHEADER_H ... #endif,或者 #pragma once)。条件编译的好处是编译器直接跳过不需要的代码,零运行时开销。

#pragma once 和 include guard 有什么区别?

#ifndef MYHEADER_H / #define MYHEADER_H / #endif 是标准 C 写法,所有编译器都支持,但要自己起宏名,可能撞名。#pragma once 更简洁,编译器用文件路径去重,不用起宏名。但 #pragma once 不是标准,理论上编译器可以不支持——实际上所有主流编译器都支持。项目里选一种统一用就行,别混着来。

宏的 # 和 ## 是干什么用的?

# 把宏参数转成字符串(字符串化),## 把两个 token 拼接成一个(token 粘合):

c
#define STR(x) #x // STR(hello) → "hello" #define CONCAT(a, b) a##b // CONCAT(var, 1) → var1

在生成枚举名称、注册函数表这些元编程场景中偶尔用到,日常代码很少用。面试知道就行,别主动写这种代码。

预处理和编译是什么关系?

编译分四个阶段:预处理 → 编译 → 汇编 → 链接。预处理阶段只做文本操作(替换宏、插入头文件、删除条件编译排除的代码),不检查语法。所以宏写错了,报错信息可能非常难懂——因为编译器看到的是展开后的代码,不是你写的源码。gcc -E file.c 可以查看预处理后的结果,调试宏时很有用。

标签:C语言