
C语言提供的预处理指令主要有3种:宏定义、文件包含和条件编译等。
1.宏定义
宏定义的作用是用宏名来代替一个字符串,宏名由标识符构成,通常采用大写字母来表示。一旦对字符串命名,就可以在源程序中使用宏名,以达到简化程序书写的目的。C编译系统在编译之前会将标识符替换成字符串。
(1)不带参数的宏
不带参数的宏定义形式:#define 宏名 字符串
define是关键字,表示宏定义。
宏名必须符合标识符的定义,为了区别于变量,宏名一般采用大写字母,如:#define PI 3.14159。
宏的作用:在程序中的任何地方都可以直接使用宏名,编译器会先将程序中的宏名用字符串替换,然后再进行编译。这个过程叫宏替换,宏替换不进行语法检查。
宏名的有效范围是从定义命令之后,直到源程序文件结束,或遇到宏定义终止命令#undef为止。
【例6-12】阅读以下程序,了解不带参数的宏的作用。
#include <stdio.h>
#define TEST "This is a test!"
int main()
{
printf(TEST);
printf("\n");
printf("TEST");
#undef TEST
return 0;
}
程序运行结果:
This is a test!
TEST
编译系统遇到TEST时,就用” This is a test!”替换,但是如果是字符串中包含宏名则不会进行替换。#undef命令可以用来终止宏定义的作用域。
(2)带参数的宏
带参数的宏定义形式:#define 宏名(参数表) 字符串
字符串应包含有参数表中的参数。
宏替换时,是将字符串中的参数用实参表中的参数进行替换。
【例6-13】阅读以下程序,了解不带参数的宏的作用。
#include <stdio.h>
#define F(a) a*b
int main()
{
int x=4,y=5;
int b,z;
b=(x-y);
z=F(x+y);
printf("b=%d\nF(x+y)=%d\n",b,z);
return 0;
}
程序运行结果:
b=-1
F(x+y)=-1
这个程序的结果可能并不是我们想要得到的,因为z=F(x+y)这个语句在编译之前会被替换成z=x+y*b;其结果自然就是-1。如果我们希望将z=F(x+y)替换成z=(x+y)*b,那么我们之前宏定义要改写成:#define F(a) (a)*b,这样就可以避免二义性。
2.文件包含
在一个源文件中使用#include指令可以将另一个源文件的全部内容包含进来,也就是将另外的文件包含到本文件之中。在对源文件进行编译之前,用包含文件的内容取代该预处理命令。
文件包含命令的一般形式为:
#include <包含文件名>
或
#include "包含文件名"
(1)include是命令关键字,表示文件包含,一个include命令只能包含一个文件。
(2)<>表示被包含文件在标准目录中。
(3)""表示被包含文件在指定的目录中。如果文件名不带路径,则在当前目录中,若找不到,再到标准目录中寻找。
(4)包含文件名可以是.c源文件或.h头文件。
【例6-14】阅读以下程序,理解文件包含命令的作用。
1.file1.c
int sum(int a,int b)
{
return a+b;
}
2.file2.c
int dif(int x,int y)
{
return x-y;
}
3.example6-14.c
#include <stdio.h>
#include “file1.c”
#include “file2.c”
int main(){
int result;
result=sum(9,5)*dif(9,5);
printf(“result=%d\n”,result);
return 0;
}
程序运行结果:
result=56
3.条件编译
一般情况下,源程序中所有的行都参加编译,但是有时希望部分代码行在满足一定条件时才进行编译,这时就需要使用一些条件编译命令。
(1)#if指令,用于判断是否满足给定条件的编译形式。主要包含以下形式:
#if<表达式>
语句段1
[#else
语句段2]
#endif
作用:如果“表达式”的值为真,则编译“语句段1”,否则编译“语句段2”,方括号表示表示可以缺省,不论是否有#else,#endif都是必不可少的。另外一种形式:
#if<表达式1>
语句段1
#else if <表达式2>
语句段2
#else
语句段3
#endif
其作用与if分支语句相似,只要符合嵌套规则就可以,但是这里是条件编译,只有符合条件的代码段才能被编译。
(2)#ifdef和#ifndef指令:用于判断是否有宏定义的条件编译。
#ifdef的一般形式:
#ifdef 宏名
语句段
#endif
如果在此之前已经定义了这样的宏名,则编译语句段。
#ifndef的一般形式
#ifndef 宏名
语句段
#endif
如果在此之前没有定义这样的宏名,则编译语句段。