第六章预处理功能能和类型定义

预处理功能是由很多预处理命令组成,这些命令在编译时进行通常的编译功能(包含词法和语言分析、代码生成、优化等)之前进行处理。预处理后的结果和源程序一起在进行通常的编译操作,进而得到目标代码。

预处理功能主要包括:宏定义、文件包含、条件编译。

特点:1)只是替代功能,不进行语法检查;2)预处理命令在通常编译之前进行,即对预处理里后的结果进行编译,这时进行词法和语法分析;3)预处理命令后不加分号;4)预处理命令都以#号开头。

1.宏定义(分为带参数和不带参数)

简单宏定义

格式如下:

#define(标识符){字符串}

其中,define是关键字,他表示该命令为宏定义,(标识符)是宏名,{字符串}用来表示(标识符)所代表的字符串。

举个例子:

# include

# definePi 3.1415926

intmain()

{

float r,s;

printf(“输入半径:”);

scanf(“%f”,&r);

s=pi*r*r;

printf(“面积s=%.4f\n”,s);

getchar();getchar();

}

结果为:

f23022c184d5d4ce800ecb91184f7d65.png

使用简单宏定义的注意事项:1)标识符一般用大写与变量区别;2)宏定义命令后不加分号;3)宏定义不做语法检查;4)宏定义中宏名作用域为定义该命令的文件中,并从定义时起,到终止宏定义命令(#undef(标识符))为止,如果没有终止宏定义命令,则到该文件结束为止;5)宏定义可以嵌套。

带参数的宏定义

格式如下:

#define(宏名) (参数表)(宏体)

其中(参数表)是由一个或多个参数组成的,多个参数之间用逗号分隔开;(宏体)是一个字符串,其中包括(参数表)中所指定的参数,他可以是有若干个语句组成的。该命令末尾一般不加分号。(带参数的宏定义在宏替换时,不是简单地用宏替换宏名,而是用“实参”(程序中引用宏名的参数)替换“形参”(宏定义时参数表中的参数))。

举个例子:

# include

# defineSQ(x) x*x

intmain()

{

int a=SQ(5);

printf(“a=%d”,a);

getchar();

}

结果为:

230665f550de9ece7e1816267281fb34.png

注意事项:

在宏定义时,宏名与左圆括号之间不能出现空格,否则将把空格视为宏体的一部分。

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

1)定义形式上不同;

2)处理时间上不同(宏定义是处理后再编译,函数为执行时处理的);

3)处理方式不同(宏只是简单替换,并不做语法检查,宏定义中参数替换不要求类型一致,函数要求形参,实参对应类型一致);

4)时间和空间上的开销不同;

5)类型要求不同(带参数的宏定义时对形参类型不用说明,他没有类型的限制,函数的形参在定义时必须进行类型说明)。

宏定义的应用

1)符号常量的定义;

2)功能简单使用频繁的情况下使用;

3)为了书写简练,程序易读。

2.文件包含

格式如下:

#include(文件名)

其中,include是关键字,(文件名)是被包含的文件名,这里要求使用文件全名,包括路径名和扩展名。

文件包含的功能就是将指定的被包含文件的内容放置在文件包含命令出现的地方,一般放在程序的开头。

举个例子:

#defineF1 “%d\n”//print.h

#defineF2 “%d,%d\n”

#definePR1(a) printf(F1,a)

#definePR2(a,b) printf(F2,a,b)//print.h

# include//主程序

# include

intmain()

{

int x,y,z;

x=5;

y=5*x;

z=x+y;

PR1(x);

PR2(y,z);

PR1(2*y);

PR2(x+5,z/5);

getchar();

}//主程序

结果为:

bf21424d14713a6e86a064d878779374.png

注意事项:1)一个文件包含命令只能包含一个文件;2)文件包含是可以嵌套的

3.条件编译

条件编译指的是对编译的程序的某种控制,在某种条件下,源程序中的这些行参加编译;而在另一种条件下,源程序中那些形参加编译,即根据不同的条件来控制源程序参家编译的内容。

格式如下:

#ifdef(标识符)

(程序段1)

#else

(程序段2)

#endif

其中,ifdef,else,endif是关键字,(标识符)是指是否使用#defin命令定义过(当(标识符)被宏定义时,(程序段1)中的语句或命令参加编译;否则(程序2段)中的语句或命令参加编译(其中#else可省))。

另一种格式:

#ifndef(标识符)

(程序段1)

#else

(程序段2)

#endif

只是与第一种格式的第一个关键字不同表示(如果(标识符)未被宏定义,则编译(程序段1),否则编译(程序段2)。

第三种格式:

#if(表达式)

(程序段1)

#else

(程序段2)

#endif

该格式的功能是:当(表达式)是非0时,则编译(程序段1),否则(程序段2)参加编译。)

4.类型定义

类型定义:根据某种需要对已有的类型用一种新的类型名字来代替(给已有或已存在的类型起个新名字,而不是再重新定义一个原来没有的类型)

格式如下:

Typedef(已有类型说明符)(新类型名表);

注意事项:

1)习惯上将新定义的类型名用大写字母;

2)类型第一可以嵌套;

3)常把使用该语句定义的数据类型包含在某个头文件中,在不同的源文件中用到该类型时,可以使用文件包含命令将所需要的头文件包含到该源文件中。

下面我们来举个例子来区别一下typedef语句和#define命令的不同:

# include

typedefint INT;

intmain()

{

INT a,b;

a=5;

b=6;

printf(“a=%d,b=%d\n”,a,b);

{float INT;

INT=3.0;

printf(“2*INT=%.2f\n”,2*INT);

getchar();

}

}

结果为:

3d02c59b3377998ffa6c1a72ca6ad431.png

# include

#defineINT int

intmain()

{

INT a,b;

a=5;

b=6;

printf(“a=%d,b=%d\n”,a,b);

#undefINT

{

float INT;

INT=3.0;

printf(“2*INT=%.2f\n”,2*INT);

getchar();

}

}

结果为:

2b305d6f5f94d02d3ae4b6254b8d5342.png