ANSI C标准规定可以在C源程序中加入一些“预处理命令”,以改进程序的涉及环境,提高编程效率。
预处理命令不是C语言本身的组成部分,不能直接对它们进行那个编译。必须在进行编译之前根据预处理命令对程序作相应的处理。
经过预处理之后的程序就不再包括预处理命令了。
(预处理过程还会删除程序中的注释和多余的空白字符?)
C语言主要提供3种预处理功能:
1.宏定义;
2.文件包含;
3.条件编译。
为了与一般的C语句区别,预处理命令以“#”开头,“#”号必须是该行除了任何空白字符外的第一个字符,“#”后是指令关键字,在关键字和#号之间允许存在任意个数的空白字符,整行语句构成了一条预处理指令。
1.宏定义
不带参数的宏定义
#define 标识符 字符串
说明:
(1) 宏名一般习惯用大写,与变量名相区别。
(2) 宏定义是用宏名代替一个字符串,是简单的置换,并不作正确性检查。
(3) 宏定义不加分号。
(4)#undef 命令可以终止宏定义的作用域。
(5)宏定义可以嵌套。
(6)对程序中用双撇号括起来的字符串内的字符,即使与宏名相同,也不进行替换。
(7)宏定义不占内存。
带参数的宏定义
#define 宏名(参数表) 字符串
带参数时,宏定义不是进行简单的字符替换,还要进行参数替换。
说明:
(1) 为了不出错,在宏定义的字符串中的形参外面加一个括号。
(2) 宏名和带参数的括号之间不应加空格。
(3) 带参数的宏定义与函数是不同的:
函数调用时,要先求出实参表达式的值,然后带入形参,而宏只是简单的替换;
函数调用是程序运行时处理的,要为形参分配临时内存单元,而宏则是在编译之前进行的,不占用内存,也没有返回值的概念;
函数只能有一个返回值,宏可以有多个返回值;
使用宏的次数越多,源程序就越长,而函数调用不会是源程序变长;
#运算符
出现在宏定义中的#运算符把跟在其后的参数转换成一个字符串。
#define STR(n) "I am "#n
int main()
{
printf("%s", STR(81));
return 0;
}
//output:
I am 81
(##运算符
##运算符用于把参数连接到一起,预处理程序把出现在##两侧的参数合并成一个符号。)
2.文件包含处理
#include "文件名"
双撇号形式:系统现在用户当前目录中寻找要包含的文件,若找不到,再按照标准方式查找。
#include <文件名>
尖括号形式:系统将存放在C库函数头文件的目录综合那个寻找要包含的文件(标准方式)。
将另外一个源文件的全部内容包含到本文件中。
说明:
(1) 在编译时,并不是对各个文件分别编译,而是经过预处理后将头文件包含到主文件中,得到一个新的源程序然后对这个源程序进行编译得到一个目标文件。被包含的文件成为新的源文件的一部分;
(2) 文件包含是可以嵌套的;
(3) 文件包含需要按顺序在文件中说明。
3.条件编译
有时候希望程序中的一部分内容只在满足一定条件的条件下才进行编译,即条件编译。条件编译可以提高C程序的通用性,减少要编译的语句,从而减少目标程序的长度,减少运行时间。
#ifdef 标识符
程序段1
#else
程序段2
#endif
若所指定的标识符已经在#define命令定义过,则在程序编译阶段编译程序段1,否则就编译程序段2。
#ifndef 标识符
程序段1
#else
程序段2
#endif
若标识符未被定义过,则编译程序段1,否则编译程序段2。
#if 表达式
程序段1
#else
程序段2
#endif
若表达式为真,则编译程序段1,否则编译程序段2。