编译预处理

来源:互联网 发布:英语语义学 知乎 编辑:程序博客网 时间:2024/05/18 01:35

什么是预处理?
预处理是指在编译之前对程序中的特殊命令进行的处理工作。以#开头的是C语言的编译预处理命令。

C语言中编译预处理的分类

  • #define 宏定义
  • #include 文件包含
  • #if() 条件编译

这些编译预处理指令不是C语言的成分,不仅C语言可以使用这些预处理指令,其他语言也可以使用。

运行程序时需要经历哪些步骤?

运行程序时需要进行如下的步骤:
- C语言在编译之前需要进行一个预处理的步骤,因此C语言的编译系统中包含一个预处理程序和一个编译程序。所以我们要运行一个程序首先要把我们编好的*.c源程序文件交给预处理程序进行处理。
- 预处理程序把这些预处理的命令处理好、替换好然后交给编译程序。
- 编译程序进行编译最后生成目标程序*.obj。
- (步骤:源程序.c —> 预处理 —>编译 —>目标程序.obj

宏定义
格式:#define 宏名 字符串
功能:在预处理时,将程序中宏定义之后出现的宏名,用宏替换字符串(宏名之后的那个字符串)代替。将宏名替换成字符串的过程也称宏展开。
说明:

  • 宏定义通常放在程序开始的位置,并且以#开头,末尾不加分号(不是C程序的语句)。
  • 宏名一般用大写字母来表示。
  • 一个宏名只能被定义一次。
  • 宏定义的作用域是从定义开始到程序的结尾。

优点:可提高源程序的可维护性、可移植性,减少源程序中重复书写字符串的工作量。

带参数的宏定义
格式:#define 宏名(形参表) 字符串
功能:预处理程序对程序中所有带实参表的宏名进行宏展开替换。
有参宏的调用和宏展开:
调用格式: 宏名(实参表)
宏展开:首先进行宏展开,然后用宏调用提供的实参字符串,直接置换宏定义命令行中相应形参字符串,非形参字符保持不变。
例子:

#include<stdio.h>#define X(a) a*aint main(){    printf("%d\n",X(4+5));    return 0;}

上述程序执行的结果为29,这是因为程序在执行时会调用实参4+5,并将4+5直接置换为宏定义命令行中相应形参的字符串即 4+5*4+5,因为这里面的4+5就是形参a,宏展开时是“忠实的”展开,如果想要上面程序运行的值为81还需要再宏定义命令行相应形参上扩上括号,代码如下:

#include<stdio.h>#define X(a) (a)*(a)    //注意这里int main(){    printf("%d\n",X(4+5));    return 0;

上述程序的执行结果为81,其宏展开时将实参放入到相对应的形参位置上(4+5)*(4+5),结果为81。注意在宏展开时,只是简单的将实参作为一个字符串。

带参数的宏与函数的区别:

  • 函数调用时,先计算实参表达式的值,再代入形参;宏定义展开则为纯文本替换;
  • 函数调用在程序运行时处理,分配临时的储存单元;宏展开则在编译时进行,展开时不分配内存单元,不传递值,无“返回值”概念;
  • 函数调用影响运行时间,源程序无变化;宏展开影响编译时间,通常使源程序加长。

终止宏定义
在程序中如果想终止宏定义的作用,可以使用终止宏定义命令。
格式:#undef 宏名

文件包含
文件包含(#include)是指一个源文件可以将另一个源文件的全部内容插入到它所在的位置。
两种格式:

  • #include”文件名”
  • #include<文件名>

第一种格式表示在查找包含文件时先在当前目录下查找,如果没有找到的话,再到系统指定的目录下查找。第二种格式表示直接在系统指定的目录下查找包含的文件。
注意:

  • 文件包含时只能包含源文件,不能包含可执行文件和目标文件。
  • 一个#include命令只能包含一个文件。
  • 我们可以将常用的符号常量、带参数的宏定义、外部变量及构造类型的变量等定义在一个独立的文件中,为其他文件共享。

条件编译
通常情况下源程序中的所有行都参与编译,C允许有选择的选择编译的程序行。条件编译就是C语言提供给我们的这样的一个工具,程序中的一部分内容在满足一定条件下才能进行编译,即对一部分内容指定编译条件。
作用:可有效的提高程序的可移植性,并广泛的应用在商业软件中,为一个程序提供各种不同的版本。
两种格式:

//格式1#if 表达式    程序段1#else    程序段2#endif

当表达式为非0时,编译程序段1,否则编译程序段2;

//格式2#ifdef 宏名    程序段1#else    程序段2#endif

当宏名已被#define命令定义过,则编译程序段1,否则编译程序段2。

原创粉丝点击