预处理命令是C++统一规定的,但是它不是C++语言本身的组成部分,不能直接对它们进行编译。因此必须在对程序进行通常的编译之前,先对程序中这些特殊的命令进行“预处理”,根据预处理命令对程序作相应的处理。经过预处理后,再由编译程序对预处理后的源程序进行通常的编译处理,得到可供执行的目标代码。
C++提供的预处理功能主要有以下3种:
(1)宏定义
(2)文件包含
(3)条件编译
分别用各种命令来实现,为了与一般C++语句相区别,这些命令以符号“#”开头,而且末尾不包含分号。
1.宏定义
可以用#define命令将一个指定的标识符来代表一个字符串。作用是用一个短的名字代替一个长的字符串。
它的一般形式为:
#define 标识符 字符串
如:
#define PI 3.1415926
它的作用是指定用标识符PI来替代“3.1415926”这个字符串。
在编译预处理时,在该命令以后出现的所有PI都用“3.1415926”代替。
在c语言中用#define定义符号常量,而C++中增加了const语句来定义常变量。
还可以用#define命令来定义带参数的宏定义。
#define 宏名(参数表) 字符串
如:
#define S(a,b) a*b
由于C++中增加了内置函数(inline),比用带参数的宏定义更方便,因此C++中基本不再用#define命令定义宏了,主要用于条件编译中。
2.“文件包含”处理
所谓“文件包含”处理是指一个源文件可以将另外一个源文件的全部内容包含进来。
C++提供了#include命令来实现“文件包含”的操作。
include命令有两种形式:
#include <文件名>
或
#include “文件名”
两者是有区别的。用尖括号(如<iostream>)时,系统到系统目录中寻找要包含的文件,如果找不到编译系统就给出错误信息。
如果要包含的是C++系统提供的头文件,应该用这种形式。
另外一种情况是,用户自己编写的被包含的文件往往存放在自己指定的目录中,这时应该用双撇号形式。
在双撇号中指出文件路径和文件名,如
#include"C:\tan\C++\file1.c"
要求编译系统从C盘上的目录\tan\C++中寻找file.c文件,找到后用文件内容取代#include命令行,如找不到,就到系统目录中找,如果还找不到,则不再寻找,给出出错信息。
如果双撇号中没有给出绝对路径,如
#include"file2.c"
则默认指用户当前目录中的文件。系统先在用户当前目录中寻找要包含的文件。
对于系统提供的头文件(如iostream)既可以用尖括号形式,也可以用双撇号形式,都能找到被包含的文件,但显然用尖括号形式效率更高。
关于C++标准库,新的C++标准库中的头文件一般不再包括后缀.h,例如
#include<string>
但为了使大批的C程序能够继续使用,许多C++编译系统保留了C的头文件,提供了两种不同的头文件
#include <iostream.h> //C形式的头文件
#include <iostream> //C++形式的头文件
效果基本是一样的,建议用符合C++标准的形式。
如果用户自己编写的头文件,可以用后缀.h。
3.条件编译
一般情况下,在进行编译时对程序中的每一行都要编译。但是有时希望程序中某一部分内容只在满足一定条件时才进行编译,也就是指定对程序中的一部分内容进行编译的条件。如果不满足这个条件,就不编译这部分内容。
条件编译命令常用的有以下形式:
(1)#ifdef 标识符
程序段1
#else
程序段2
#endif
它的作用是当所指定的标识符已经被#define命令定义过,则在程序编译阶段只编译程序段1,否则编译程序段2.
#endif用来限定#ifdef命令的范围。其中#else部分也可以没有。
(2)#ifndef 标识符
程序段1
#else
程序段2
#endif
只是第一行与第一种形式不同:将ifdef改为ifndef,其中n代表not。它的作用是若标识符未被定义过,则编译程序段1,否则编译程序段2.
(3)#if 表达式
程序段1
#else
程序段2
#endif
它的作用是当指定的表达式值为真(非零)时就编译程序段1,否则编译2.