This post has a total of 1276 words, and is expected to take 2 minutes 8 seconds to read.文章篇幅适中,可以放心阅读。

7 编译预处理

编译预处理,是在编译源程序之前,对源代码进行的加工和处理工作。

编译预处理的作用是对源文件中的预处理命令进行处理,生成中间文件,编译器再对中间文件进行编译,进而生成目标代码。目标代码中并不包含预处理命令。

C++ 中的预处理功能,主要包括 宏定义文件包含条件编译 三种。

7.1 宏定义

在 C++ 语言源程序中允许用一个标识符来表示一个字符串,称为“宏”。被定义为“宏”的标识符称为“ 宏名 ”。在编译预处理时,对程序中所有出现的宏名,都用宏定义中的字符串去代换,这称为“ 宏代换 ”或“ 宏展开 ”。

7.1.1 不带参数的宏定义

无参宏定义的一般形式为

# define 宏名 字符串

其中的“#”表示这是一条预处理命令。“define”为宏定义命令。“宏名”为用户定义的标识符。

说明:

  1. 宏展开只是机械地进行文本替换,不是语句,不需要在其后加 “;”。如果有分号,分号也会成为替换文本的一部分,容易出现语法错误。
# define PI 3.14;
double area = PI * r * r;
// 经过宏展开后
// area = 3.14; * r * r;
  1. 宏定义的有效范围是定义处到本源文件结束。可以使用 #undef 提前终止其作用域。
# define PI 3.14;
double f1(){...}
# undef
  1. 宏定义不会替换代码中的字符串内容。

7.1.2 带参数的宏定义

C++ 语言允许宏带有参数。在宏定义中的参数称为 形式参数 ,在宏调用中的参数称为 实际参数 。对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参。

带参宏定义的一般形式为

# define 宏名(形参表) 字符串

带参宏调用的一般形式为

宏名(实参表)

示例:

# define S(a, b) a * b
double area = S(3, 2);
// 经过宏展开后
// area = 3 * 2;

说明:

  1. 需要警惕生产语意错误。
# define S(a, b) a * b
double area = S(1 + 3, 2 + 4);
// 经过宏展开后
// area = 1 + 3 * 2 + 4;
// 而我们希望的结果是
// area = (1 + 3) * (2 + 4);
  1. 带参数的宏定义与函数是不同的。宏定义在编译前被使用,不会存在于最终程序中;而函数在被调用时使用,存在于最终程序中。

7.2 文件包含

文件包含的作用,是将指定的源文件嵌入到当前源文件的该文件包含指令位置处。

文件包含命令的一般形式为

# include "文件名"# include <文件名>

文件包含命令非常重要。因为有些公用的符号常量或宏定义等可单独组成一个文件,在其他文件的开头用包含命令包含该文件即可使用。这样,可避免在每个文件开头都去书写那些公用量,从而节省时间,并减少出错。

说明:

  1. 一个 include 命令引入一个文件
  2. 包含的文件必须是文本文件,如 C++ 源文件(如:"xxx.cpp")和系统库文件(如:<iostream>)。不可以是可执行文件或者目标程序。
  3. # include <文件名> 格式,预编译器会在 C++ 系统的目录中查找要包含的文件,如果找不到则会预处理失败。
  4. # include "文件名" 格式,预编译器会在当前被编译文件所在文件夹中寻找目标文件,或者程序员可以指定首先搜索的目录,如: # include "D:/xxx/x.cpp" ,找不到再去 C++ 系统目录中寻找。

7.3 条件编译

有时,源文件中的代码并不是全部都需要进行编译。例如,我们在调试程序时,往往需要大量的输出语句,用来了解程序执行过程,而在供用户使用的程序版本中,这些输出语句就显得非常多余。

条件编译有三种形式,下面分别介绍:

7.3.1 宏名作为编译条件

# ifdef 标识符
    程序段 1
<# else
    程序段 2>
# endif

<...> 表示这部分可以没有。

它的功能是,如果标识符已被 #define 命令定义过则对程序段 1 进行编译;否则对程序段 2 进行编译。

7.3.2 宏名作为不编译条件

与第一种形式的区别是将 ifdef 改为 ifndef 。它的功能是,如果标识符未被# define命令定义过则对程序段 1 进行编译,否则对程序段 2 进行于编译。这与第一种形式的功能正相反。

7.3.3 表达式的值作为编译条件

#if 常量表达式
    程序段 1
<#else
    程序段 2>
#endif

<...> 表示这部分可以没有。

它的功能是,如常量表达式的值为真(非0),则对程序段1 进行编译,否则对程序段2进行编译。

My favorite thing is to leave this blank :)

Switch Theme | SCHEME TOOL