一、编译预处理概念
1、编译预处理不是 C 语言本身的内容,是 C 编译系统提供的功能。在通常的编译之前,编译系统要预先对这些命令进行处理,之后才对 C 程序进行编译,生成目标代码。
特别注意:所有预处理命令均以 # 开头,末尾不加分号。
2、以下是三种预处理命令:
宏定义
#define PI 3.1415926
文件包含
#include <stdio.h>
#include "c_file1.c"
条件编译
#ifdef 标识符
// TODO1
#else
// TODO2
#endif
二、宏定义 & 文件包含 & 条件编译
1、宏定义
宏定义可以分为两种:1、不带参数的宏定义;2、带参数的宏定义。二者都是简单的字符串替换。
① 不带参数的宏定义
// 不带参数的宏定义方式
#define 标识符 一串字符
// 例如(以下宏定义中 PI 即为“宏名”):
#define PI 3.1415926
// 宏定义的作用:用 “标识符” 后的 “一串字符” 来替换程序中的 “标识符”
// 例如:#define PI 3.1415926
// 表示用 3.1415926 替换程序中的所有标识符 PI
// 参考代码
#include <stdio.h>
#define PI 3.1415926
int main(int argc, const char * argv[]) {
// r 表示半径;l 表示周长; s 表示面积
double r = 6, l = 0, s = 0;
l = 2 * PI * r; // 计算周长
s = PI * r * r; // 计算面积
printf("周长 = %.2f; 面积 = %.2f\n", l, s);
// ★★★特别提醒:双引号中的 PI 不会被替换为 3.1415926
// 双引号引起来的字符串常量中出现了与宏名相同的内容,不能将其理解为宏名,更不能将其展开。
printf("PI = %.7f\n", PI);
return 0;
}
/*
以上代码运行结果如下:
周长 = 37.70; 面积 = 113.10
PI = 3.1415926
*/
*** 在预处理时,先做如下替换,然后才开始编译:***
l = 2 * PI * r; 会被替换成 l = 2 * 3.1415926 * r;
s = PI * r * r; 会被替换成 s = 3.1415926 * r * r;
*** 特别提醒:***
1> 宏名前后应有空格
2> 宏定义是用宏名代替一个字符序列,只是一种简单的替换,不进行正确性检查。
例如:
#define PI = 3.14abc15926
s = PI * r * r;
// 以上代码在预编译时只做替换操作,不会出错。在编译时才会报错。因为 3.14abc15926 不是合法的数字。
*** 易错提醒:***
宏定义时,为了保证计算正确性,需要适时加小括号。
#define PI 2 + 1.1415926
s = PI * r * r;
// s = PI * r * r; 展开后形式是:s = 2 + 1.1415926 * r * r; 由于运算符优先级问题此时计算的结果 s 是错误的。
// 应该将宏定义改为:
#define PI (2 + 1.1415926)
// 此时,s = PI * r * r; 展开后形式是:s = (2 + 1.1415926) * r * r; 计算结果正确
*** 嵌套宏定义 😗**
#include <stdio.h>
#define PI 3.1415926
#define RADIUS 3.0
#define AREA PI * RADIUS * RADIUS
int main(int argc, const char * argv[]) {
printf("area = %f\n", AREA); // 输出结果为:area = 28.274333
return 0;
}
/*
以上宏展开的过程:
1. 首先对 #define AREA PI * RADIUS * RADIUS 中的 AREA 展开得到:#define AREA 3.1415926 * 3.0 * 3.0
2. 再对 printf("area = %f\n", AREA); 中的 AREA 展开得到:
printf("area = %f\n", 3.1415926 * 3.0 * 3.0);
*/
*** 宏名的作用范围:***
宏名的作用域是从定义点开始到本源文件结束,或用 #undef 取消定义之前。例如:
#define PI 3.1415926
#define G 9.8
int main(int argc, const char * argv[]) {
// 在 main() 函数中 PI 和 G 均可以正常使用
}
// 以下这行代码取消了宏 G 的定义
#undef G
void func() {
// 在该函数中只能使用宏 PI,而不能使用宏 G 了
}
// 宏 G 的作用域是从定义点开始到 #undef G 之前。
// 宏 PI 的作用域是从定义点开始到本源文件结束。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)