什么是预处理命令?
预处理命令属于C语言编译器,而不是C语言的组成部分
预处理命令的作用:就是在编译和链接之前,对源文件进行一些文本方面的操作,比如文本替换、文件包含、删除部分代码等,这个过程叫做预处理
预处理命令可以改变程序设计环境,提高编程效率,它们并不是C语言本身的组成部分,不能直接对它们进行编译,必须在对程序进行编译之前,先对程序中这些特殊的命令进行“预处理”。经过预处理后,程序就不再包括预处理命令了,最后再由编译程序对预处理之后的源程序进行编译处理,得到可供执行的目标代码。
(预先处理的部分,在程序进行编译之前运行)
预处理命令的特点:
(1)命令以#开头;
(2)每条命令独占一行;注释可以与指令(命令)放在同一行
(3)命令不以“;”为结束语
功能:
(1)将源文件中以”include”格式包含的文件复制到编译的源文件中。
(2)用实际值替换用“#define”定义的字符串。
(3)根据“#if”后面的条件决定需要编译的代码
工作方式:
预处理的行为是由指令控制的。这些指令是由#字符开头的一些命令。
预处理器的输入是一个C语言程序,程序可能包含指令。预处理器会执行这些指令,并在处理过程中删除这些指令。预处理器的输出是另外一个程序:原程序的一个编辑后的版本,不再包含指令。预处理器的输出被直接交给编译器,编译器检查程序是否有错误,并经程序翻译为目标代码。
什么是宏定义?
在 C 语言源程序中允许用一个标识符来表示一个字符串,称为“宏”。被定义为“宏”的标识符称为“宏名”。在编译预处理时,对程序中所有出现的宏名,都用宏定义中的字符串去代换,这称为“宏代换”或“宏展开”。
注:宏定义不占内存空间,因为宏在预处理阶段就会被替换掉,到了编译的阶段是没有宏存在的,它在预编译阶段就被处理了
#define:
(无参宏定义)一般形式:
#define 标识符 字符串;
(字符串”可以是常数、表达式、格式串等)
注:不管是在某个函数内,还是在所有函数之外(不太建议把#define写在函数内),#define作用域都是从定义开始直到整个文件
带参宏定义:
(带参宏定义)一般形式:
#define 宏名(形参表) 字符串
其中字符串包含各个形参
带参宏定义调用:
带参宏定义调用一般形式:
宏名(实参表);
#include
#define MAX(x,y) ((x) > (y) ? (x) : (y))
int main(void)
{
printf("Max between 20 and 10 is %d\n", MAX(10, 20));
return 0;
}
输出结果:Max between 20 and 10 is 20
宏替换相当于实现了一个函数调用的功能,而事实上,与函数调用相比,宏调用更能提高C程序的执行效率
#undef
作用:取消之前的宏定义(也就是#define的标识符)
#undef 标识符
注:如果标识符当前没有被定义成一个宏名称,那么就会忽略该指令
宏延续运算符(\):
一个宏通常写在一个单行上。但是如果宏太长,一个单行容纳不下,则使用宏延续运算符(\)。例如:
#define message_for(a, b) \
printf(#a " and " #b ": We love you!\n")
字符串常量化运算符(#):
在宏定义中,当需要把一个宏的参数转换为字符串常量时,则使用字符串常量化运算符(#)。在宏中使用的该运算符有一个特定的参数或参数列表。
例如:
#include
#define message_for(a, b) \
printf(#a " and " #b ": We love you!\n")
int main(void)
{
message_for(Carole, Debra);
return 0;
}
输出结果:Carole and Debra: We love you!
标记粘贴运算符(##):
宏定义内的标记粘贴运算符(##)会合并两个参数。它允许在宏定义中两个独立的标记被合并为一个标记。
例如:
#include
#define tokenpaster(n) printf ("token" #n " = %d", token##n)
int main(void)
{
int token34 = 40;
tokenpaster(34);
return 0;
}
输出结果:token34 = 40
一般形式:
#include<文件名>
或
#include"文件名"
区别:头文件的搜索路径不同
尖括号(<>):编译器会到系统路径下查找头文件
(表示在包含文件目录中去查找(包含目录是由系统的环境变量进行设置的,一般为系统头文件的默认存放目录,比如Linux系统在/usr/include目录下),而不在源文件的存放目录中查找)
双引号(""):编译器会先在当前目录下查找头文件,如果没有找到,再到系统路径下查找
(表示首先在当前的源文件目录中查找,若未找到才到包含目录中去查找)
功能:
把指定的文件插入该命令行位置取代该命令行,从而把指定的文件和当前的源程序文件连成一个源文件。因为有些公用的符号常量或宏定义等可单单独组成一个文件,在其他文件的开头用包含命令包含该文件即可使用。
#include所包含的文件,其扩展名可以是“.c”,表示包含普通C语言源程序。也可以是 “.h”,表示C语言程序的头文件
注:
(1)头文件只能包含变量和函数的声明,不能包含定义,否则在多次引入时会引起重复定义错误
(2)一个include命令只能指定一个被包含头文件,若有多个头文件要包含,则需用多个include命令。
(3)头文件包含允许嵌套,即在一个被包含的文件中又可以包含另一个文件
头文件是扩展名为 .h 的文件,包含了 C 函数声明和宏定义,被多个源文件中引用共享
有两种类型的头文件:程序员编写的头文件和编译器自带的头文件
引用头文件相当于复制头文件的内容
注:在程序中要使用头文件,需要使用 C 预处理指令 #include 来引用它
预处理程序提供了条件编译的功能,可以按不同的条件去编译不同的程序部分,因而产生不同的目标代码文件,这对于程序的移植和调试是很有用的。
个人认为条件编译就是判断那个程序段(文件)能否运行
引用:C 预处理器 | 菜鸟教程 (runoob.com)
C 头文件 | 菜鸟教程 (runoob.com)
(11条消息) C语言预处理命令#if、#endif、#undef、#ifdef、#else、#elif——学习总结笔记_#ifdef在哪本书里学到_越吃越胖的黄的博客-CSDN博客
(11条消息) C语言中的预处理详解_c语言预处理是什么意思_BruceZhang的博客-CSDN博客
编译预处理—C语言 - 知乎 (zhihu.com)
C语言宏定义define的用法 - C语言教程 - C语言网 (dotcpp.com)
C语言文件包含include的用法 - C语言教程 - C语言网 (dotcpp.com)
C语言条件编译的用法 - C语言教程 - C语言网 (dotcpp.com)
其他预处理命令 - C语言教程 - C语言网 (dotcpp.com)