一 预处理概述
1、前面各章中,已经多次使用过 #include 命令。使用库函数之前,应该用#include引入对应的头文件。这种以 #号开头的命令 称为预处理命令。
2、C语言提供了多种预处理功能,如 宏定义、文件包含、条件编译 等。合理地使用预处理功能编写的程序便于阅读、修改、移植和调试,也有利于 模块化程序设计。
在C语言中,宏(Macro)是一种预处理器指令,它用于定义和展开代码片段。宏可以在程序代码中以宏名称的形式出现,并在编译之前由预处理器进行替换。宏可以用来简化代码、提高可读性、实现代码复用等。
宏的定义使用 #define
关键字,后面跟着宏的名称、参数列表(可选)和宏的替换文本。宏的替换文本可以包含任何有效的C代码,它可以是 表达式、语句、函数调用等。
宏的展开是在编译之前由预处理器完成的,它将代码中所有使用该宏的地方替换为宏的替换文本。展开是简单的文本替换,不进行语法分析或类型检查。
宏可以接受参数,参数可以在宏的替换文本中使用,并在宏的调用处进行实际的替换。参数可以是任何有效的C表达式,包括常量、变量、函数调用等。
宏的使用可以提高代码的灵活性和效率,但也需要谨慎使用。宏展开可能导致意想不到的结果,宏参数的使用可能导致副作用,宏定义的作用域和生命周期可能导致代码行为不符合预期。因此,在使用宏时需要注意遵循一些编码规范和最佳实践,以确保代码的正确性和可维护性。
二 宏定义
1、在C语言源程序中允许用一个标识符来表示一个字符串,称为“宏”。被定义为“宏”的标识符,称为“宏名”。
2、在编译预处理时对程序中所有出现的“宏名”,都用宏定义中的字符串去进行 文本替换,这称
为“宏代换”或“宏展开”。
2.1 无参宏定义
1、无参宏的宏名后不带参数,一般形式为:
#define 标识符 字符串
注意1:“字符串”可以是常量、表达式
2、举例
#define PI 3.14
#define EXP x*10*1.5
编译器在预处理时,会将源程序中所有的“PI”替换成“3.14”, 将所有的EXP, 替换成表达式“x*10 *1.5,下面我们来验证一下:
#include <stdio.h>
#define PI 3.14
#define EXP x*10*1.5
int main()
{
float f;
f = 10*PI;
printf("view the data f: %f\n", f);
float f2;
// f2 = 10*EXP;
return 0;
}
先将 gcc 所在的文件夹添加到 环境变量 中。
我们可以在CLion的“Terminal”下输入编译命令:gcc -E main.c -o main.i, 通过预处理将main.
c 编译成 main.i 文件,下面我们可以打开main.i文件,看看里边的内容。
3、我们发现在刚才的代码中,宏定义中出现了x,但是我们在使用时却没有定义x变量,预处理还是能够顺利通过,这是为什么呢?
宏定义是简单的文本替换,不会做语法检查 !!!
2.2 有参宏定义
1、C语言 允许宏带有参数。在宏定义中的参数称为 形式参数,在宏调用中的参数称为实际参数。
2、对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参。带参宏定义的一般形式为:
#define 宏名(形参表) 字符串
3、使用方法
#define F(x) x*x*x
int main()
{
int r = F(3);
return 0;
}
2.3 宏定义注意事项
1、宏定义的 “字符串” 如果是表达式,表达式中的变量需要用 () 包含起来,因为在预处理阶段展开宏时,可能会用表达式来替换宏定义中的变量。
#define F(x) (x)*(x)*(x)
int main()
{
F(1+2);
return 0;
}
上面的例子中展开后,(1+2)*(1+2)*(1+2),如果不加()呢?展开的表达式就变成这样了
1+2*1+2*1+2*1+2,这显然不是我们想要的结果。
2、经典笔试题:使用宏定义返回两个整数中的最大值。
#define Max(a, b) (a)>(b)?(a):(b)
三 文件包含
1、在前面的学习中我们已经使用了C语言得文件包含命令,例如:#include <stdio.h>,文件包含语法格式如下:
#include <文件名>
#include "文件名"
注意:
- 使用 尖括号 表示 在开发环境的头文件目录 下查找,而不在源文件目录去查找。
- 使用双引号则表示首先在当前的源文件目录中查找,如果没有找到才到包含目录中去查找。
- “文件名” 可以是相对路径, 也可以是绝对路径,建议不要使用绝对路径。
四 条件编译
4.1、常用条件编译指令
4.2、ifdef
#ifdef 标识符
程序段 1
#else
程序段 2
#endif
它的功能是,如果标识符已被 #define 命令定义过则对程序段 1 进行编译;否则对程序段 2 进行编译。如果没有程序段 2(它为空),本格式中的#else 可以没有,即可以写为:
#ifdef 标识符
程序段
#endif
4.3、#if
经常使用 #if 0 对代码进行注释
#if 0
代码块
#endif