C语言预处理学习笔记
C语言预处理学习笔记
目录
- 预处理的基本概念
- 宏定义
- 不带参数的宏
- 带参数的宏
- 文件包含
- 条件编译
- 总结
预处理的基本概念
- 预处理:在编译前对源代码进行的文本替换和处理。
- 作用:简化代码、提高可读性、支持模块化开发。
- 预处理指令:以
#
开头,如#define
、#include
、#ifdef
。
宏定义
不带参数的宏
基本语法
#define 宏名 替换文本
示例
#define PI 3.1415926 // 将代码中的PI替换为3.1415926
特点
- 简单文本替换:不进行语法检查。
- 作用域:从定义处到文件结束,可用
#undef 宏名
终止。 - 注意事项:
- 宏名通常用大写字母。
- 替换文本末尾不加分号。
代码示例
#include <stdio.h>
#define PI 3.1415926
int main() {
float r = 4.0;
float area = PI * r * r; // 替换为 3.1415926 * r * r
printf("Area = %f", area);
return 0;
}
带参数的宏
基本语法
#define 宏名(参数) 替换文本
示例
#define MAX(a, b) ((a) > (b) ? (a) : (b)) // 返回较大值
特点
- 参数替换:宏展开时实参替换形参。
- 与函数的区别:
- 宏:编译前替换,无类型检查,不分配内存。
- 函数:运行时调用,有类型检查,分配内存。
代码示例
#include <stdio.h>
#define SQUARE(x) (x) * (x) // 计算平方
int main() {
int a = 5;
printf("%d", SQUARE(a)); // 替换为 (5) * (5)
return 0;
}
注意事项
- 括号问题:替换文本中的参数必须加括号,避免运算符优先级错误。
#define SQUARE(x) x * x // 错误示例:SQUARE(3+2) → 3+2*3+2 = 11 #define SQUARE(x) (x) * (x) // 正确示例:SQUARE(3+2) → (3+2)*(3+2) = 25
文件包含
基本语法
#include <头文件名> // 系统头文件(标准库)
#include "本地文件名" // 用户自定义文件
作用
- 代码复用:将其他文件的内容插入当前文件。
- 模块化开发:分离函数声明与实现。
示例
#include <stdio.h> // 包含标准输入输出库
#include "myheader.h" // 包含自定义头文件
注意事项
- 避免重复包含:使用条件编译防止头文件重复包含。
#ifndef MYHEADER_H #define MYHEADER_H // 头文件内容 #endif
条件编译
基本语法
指令 | 作用 |
---|---|
#ifdef 宏名 | 如果宏已定义,则编译后续代码 |
#ifndef 宏名 | 如果宏未定义,则编译后续代码 |
#if 表达式 | 如果表达式为真,则编译后续代码 |
#else | 配合 #if /#ifdef 使用 |
#endif | 结束条件编译块 |
应用场景
- 调试代码:通过宏控制调试信息的输出。
- 跨平台适配:根据平台选择不同代码。
示例
#include <stdio.h>
#define DEBUG 1 // 1表示调试模式,0表示关闭
int main() {
int x = 10;
#ifdef DEBUG
printf("调试信息:x = %d\n", x); // 仅DEBUG模式输出
#endif
return 0;
}
总结
- 宏定义:简化代码,分为不带参数和带参数两种。
- 文件包含:通过
#include
实现代码复用。 - 条件编译:根据条件选择性地编译代码。
- 注意事项:
- 宏替换是文本替换,注意括号和运算符优先级。
- 使用条件编译避免头文件重复包含。
练习题:
- 定义一个宏
PRINT_INT(n)
,打印整数n
的值。 - 使用条件编译实现:当
DEBUG
宏定义时打印调试信息,否则不打印。