预处理命令
预处理命令
1.1 宏定义
C语言标准允许在程序中用一个标识符来表示一个字符串,成为宏。标识符为宏名,在编译预处理时,将程序中所有的宏名用相应的字符串来替换,这个过程称为宏替换。
宏分为两种:
- 无参数的宏
- 有参数的宏
1.1.1 无参数宏
无参数宏定义的一般形式为:
#define 标识符字符串
“#”代表本行是编译预处理命令。define是宏定义的关键词,标识符是宏名。字符串是宏名所代替的内容,可以是常数、表达式等。
注意
宏定义和其他编译预处理命令不是以分号结尾的。
示例:如图1所示。
图1
终止宏定义命令的一般形式:
#undef 标识符
undef是终止宏定义的特定字,其作用是从该命令开始,该标识符(宏名)不再代表相应字符序列,即该标识符的作用范围到此处结束。
宏定义允许嵌套。例如:
#define MIN 10
#define MAX MIN*2
定义MAX宏时使用了前面已经定义的MIN。
示例:如图2所示。
图2
1.1.2 有参数宏
有参数的宏类似于有参数的函数,其定义的一般形式为:
#define 标识符 (形参表) 字符串
如果有多个参数,像函数参数一样以逗号隔开。
在程序中使用有参数宏的形式是:标识符 (实参表)
示例:如图3所示。
图3
定义有参数的宏的时候,应该注意。
(1)宏名与形参表的圆括号之间不能有空格,否则会导致错误。例如#define M (x,y)(x)*(y),M与“(”之间不能有空格。
(2)在宏定义中,字符串内的形式参数最好用括号括起来,以避免错误。
宏定义与函数的区别
宏定义 | 函数 |
---|---|
只对字符串进行简单替换 | 是按照程序的含义来替换形式参数 |
只能用于简单的单行语句替换 | 可用于复杂运算 |
只占用编译时间,不占用运行时间,执行速度快 | 调用、参数的传递等,都要占用内存开销 |
在编译时展开,多次使用会让源程序增大 | 不管调用多少次总占用相同的源程序空间 |
作用范围从定义点开始,到源程序的末尾结束 | 无 |
有参数的宏的形式参数不是变量,不分配内存空间,无需说明数据类型 | 形式参数是变量,需要分配内存空间,在函数定义时要指明参数的数据类型 |
1.2 文件包含
文件包含是指把指定源文件的全部内容包括到当前程序文件中。
文件包含命令的一般形式为:
#include "文件名"
或
#include <文件名>
文件包含预定处理命令#include的作用是使一个源文件可以将另外一个源文件的全部内容包含进来,把指定的文件插入该命令行位置取代该命令行,从而把指定的文件和当前的源程序文件连成一个源文件。
文件包含命令中的文件名即可以用尖括号,也可以用双引号,他们的区别在于查找指定文件的位置不同。尖括号只在缺省目录里找指定文件。缺省目录是由用户设置的编程环境决定的。双引号则先在源文件所在的当前目录里查找指定文件,如果没有找到再到缺省目录里找。如果指定文件与当前编写中的源程序出现在同一个目录里,就必须使用双引号来包含该文件,否则编译程序会报告找不到指定的头文件。
1.3 条件编译
条件编译是指在特定的条件下,对满足条件和不满足条件的情况分别进行处理——满足条件时编译某些语句,不满足条件时编译另一些语句。条件编译命令有一下几种模式。
模式一:
#ifndef 标识符
程序段1
#endif
其含义是:如果没有定义标识符,则编译程序段1.
这里的程序段1既可以是语句组,也可以是命令行。
示例:
#ifndef getkey
#ifndef getkey
#include <sys/types.h>
#endif
这段代码的含义是:如果没有定义符号常量getkey,就定义该常量并且包含头文件sys/types.h。
模式二:
#ifndef 标识符
程序段1
#else
程序段2
#endif
其含义就是:如果没有定义标识符,就编译程序段1,否则就编译程序段2。
模式三:
#ifdef 标识符
程序段1
#endif
其含义是:如果定义了标识符,就编译程序段1,否则就不编译该程序段。
模式四:
#ifdef 标识符
程序段1
#else
程序段2
#endif
其含义是:如果定义了标识符,就编译程序段1,否则编译程序段2。
模式五:
#if 表达式
程序段1
#endif
其含义是:如果表达式成立,则编译程序段1,否则不编译该程序。
模式六:
#if 表达式
程序段1
#else
程序段2
#endif
其含义是:如果表达式成立,就编译程序段1,否则编译程序段2.
事实上,不用条件编译而直接使用if...else语句也可以达到该要求,但采用条件编程,可以减少被编译的语句,从而减少可执行程序的长度,缩短程序运行时间。当条件编译的程序段比较多时,可执行程度的长度可以大大减少。