八、编译预处理
1.宏定义—无参宏定义、带参宏定义
宏定义是指将一个标识符(宏名)定义为一个字符串(替换文本),在编译预处理时,对程序中出现的所有宏名都用相应的替换文本去替换,这称为宏替换或宏展
开
(1).无参宏定义
无参宏定义即定义没有参数的宏
一般形式:#define 标识符 替换文本(宏体)
(#define表示该语句行是宏定义命令,标识符为所定义的宏名(习惯上用大写字母表示),替换文本可以是常量、关键字、表达式、语句等任意字符串)
#define命令可以不包括替换文本>>>>>此时仅说明宏名已经被定义,以后可以使用
#define PI 3.1416
#define N =5 //虽语法正确,但预处理器会把N替换成=5
#define N 5; //虽语法正确,但会把N替换成5
注意:
1.习惯上宏名用大写字母表示,以便与变量名区分开
2.替换文本中可以包含任意字符
3.宏定义不是声明或执行语句,在行末不用加分号
4.一个#define只能定义一个宏,且一行只能定义一个宏
5.宏定义时若一行写不下,可用“\”续行
6.宏定义通常写在函数之外,作用域是从宏定义命令起到源程序文件结束,要终止其作用域可使用#undef命令 (#undef 标识符)
(2).带参宏定义
在宏定义中的参数称为形式参数,在引用带参宏时给出的参数称为实际参数
一般形式:#define 宏名(形参表) 替换文本
引用带参宏的一般形式:宏名(实参表)
带参宏展开时,先把宏引用替换为替换文本,再将替换文本中出现的形参用实参代替
#define MUL(a,b) (a*b) int main (void) { int c; c=MUL(3,5+1); printf("c=%d\n",c); return 0; }
注意:
1.在带参宏定义中,宏名与其后的左括号之间不能有空格,不然会变成无参宏定义
2.在带参宏定义中,替换文本中的形参以及整个替换文本通常用括号括起来
3.宏定义可以用来定义多个语句,在宏替换时,把这些语句都替换到源程序中
(3).带参宏定义与函数的区别
1.定义方式不同。带参宏使用预处理命令#define定义,函数使用函数定义
2.参数性质不同。带参宏的参数表中的参数不必说明其类型,也不分配空间;函数参数表中的参数需要说明类型并为其分配空间
3.实现方式不同。宏展开是在编译时由预处理程序完成的,不占运行时间;函数调用是在程序运行时进行,需占用一定的运行时间
4.参数传递不同。若实参为表达式,引用带参宏时只是进行简单的字符替换,不计算实参表达式的值;而参数调用时,先计算表达式的值,然后代入参数
5.返回值不同。带参宏定义无返回值;函数可以有返回值
2.”文件包含“处理
所谓文件包含,指在一个文件中包含另一个文件的全部内容,使之成为该文件的一部分,这相当于是两个文件的合并
文件包含由文件包含命令确定#include来实现,一般格式有两种:
#include <文件名> #include"文件名"
文件名是指被包含的文件,称为头文件,头文件必须是文本文件,通常以“.h”为扩展名,也可以是“.c”或其他,甚至没有扩展名也可以
头文件一般包含以下几类内容:
1.对类型的声明。
2.函数声明。
3.内置(inline)函数的定义。
4.宏定义。用#define定义的符号常量和用const声明的常变量。
5.全局变量定义。
6.外部变量声明。如entern int a;
7.还可以根据需要包含其他头文件。
注意:
1.为了程序编写规范,建议不要在头文件中定义全局变量和函数
2.一个#include命令只能包含一个头文件,若有多个文件要包含,则需要多个#include命令
3.文件包含可以嵌套,即在一个头文件中可以包含另一个头文件,但要防止重复包含的情况
4.当某个头文件的内容发生变化时,意味着包含该头文件的源程序也发生变化,需要重新编译
3.条件编译
条件编译是在编译源文件之前,根据给定的条件决定编译的范围。一般情况下,源程序中所有语句都参加编译。
有时希望在满足一定的条件时,编译其中的一部分语句,在不满足条件时编译另一部分语句>>>>>条件编译
条件编译有三种形式
1.
#ifdef 标识符
程序段1
#else
程序段2
#endif
功能:如果标识符是已被#define命令定义过的宏名,就对程序段1进行编译,否则对程序段2进行编译;如果没有程序段2,则本格式中的#else可以省略
2.
#ifndef 标识符
程序段1
#else
程序段2
#endif
功能:如果标识符未被#define命令定义过,则对程序段1进行编译,否则对程序段2进行编译
3.
#if 常量表达式
程序段1
#else
程序段2
#endif
功能:如果常量表达式的值为真,则对程序段1进行编译,否则对程序段2进行编译