编译预处理:在源程序文件中,加入, 编译预处理命令,,使编译程序在对源程序进行
通常的编译(包括词法分析、语法分析、代码生成、代码优化)之前,先对这些命令进
行预处理,然后将预处理的结果和源程序一起再进行通常的编译处理,以得到目标代码
( OBJ文件)。
C提供的编译预处理命令
宏命令( Macro)
文件包含命令( include)
条件编译命令
这些命令均以 #开头,以区别于语句。
宏( Macro)
一、不带参数的宏
一般形式,#define 标识符 字符串
如,#define PI 3.1415926
作用:用标识符(称为, 宏名, ) PI代替字符串, 3.1415926”。
在预编译时,将源程序中出现的宏名 PI替换为字符串, 3.1415926”,这一替换过程称为
,宏展开, 。
#define:宏定义命令
#undef:终止宏定义命令
[例 ]
#define PI 3.1415926
main()
{
float l,s,r,v;
printf("input radius:");
scanf("%f",&r); /* 输入圆的半径 */
l = 2.0*PI*r; /* 圆周长 */
s = PI*r*r; /* 圆面积 */
v = 4.0/3.0*PI*r*r*r; /* 球体积 */
printf("l=%10.4f\ns=%10.4f\nv=%10.4f\n",l,s,v);
}
关于宏定义的说明:
1、一般宏名用大写字母表示。(变量名一般用小写字母)。
2、使用宏可以提高程序的可读性和可移植性。如上述程序中,多处需要使用 π
值,用宏名既便于修改又意义明确。
3、宏定义是用宏名代替 字符串,宏扩展时仅作简单替换,不检查语法。语法检
查在编译时进行。
4、宏定义不是 C语句,后面不能有分号。如果加入分号,则连分号一起替换。
如:
#define PI 3.1415926;
area = P*r*r;
在宏扩展后成为:
area = 3.1315926; *r*r;
结果,在编译时出现语法错误。
5、通常把 #define命令放在一个文件的开头,使其在本文件全部有效。
( #define定义的宏仅在本文件有效,在其它文件中无效,这与全局变量不同)。
6、宏定义终止命令 #undef结束先前定义的宏名。
#define G 9.8
main()
{
}
#undef G /* 取消 G的意义 */
f1()
┆
7、宏定义中可以引用已定义的宏名。
[例 8.2]
#define R 3.0
#define PI 3.1415926
#deinfe L 2*PI*R
#define S PI*R*R
main()
{
printf("L=%f\nS=%f\n",L,S);
}
8、对程序中用双引号括起来的字符串,即使与宏名相同,也不替换。例如上例
的 printf语句中,双引号括起来 L和 S不被替换。
二、带参数的宏
一般形式:
#define 宏名(参数表) 字符串
带参数的宏在展开时,不是进行简单的字符串替换,而是进行参数替换。例、
[例 ]
#define PI 3.1415926
#define S(r) PI*r*r
main()
{ float a,area;
a = 3.6;
area = S(a);
printf("r=%f\narea=%f\n",a,area);
}
说明:
带参数的宏展开时,用实参字符串替换形参字符串,注意可能发生的错误。
比较好的办法是宏定义的形参加括号。
[例 ] 返回多个值的宏定义。
#define PI 3.1415926
#define CIRCLE(R,L,S,V) L=2*PI*R; S=PI*R*R; V=4/3*PI*R*R*R
main()
{ float r,l,s,v; /*半径、圆周长、圆面积、球体积 */
scanf("%f",&r);
CIRCLE(r,l,s,v);
printf("r=%6.2f,l=%6.2f,s=%6.2f,v=%6.2f\n",r,l,s,v);
}
输出结果,
[例 ] 输出格式定义为宏
#define PR printf
#define NL "\n"
#define D "%d "
#define D1 D NL
#define D2 D D NL
#define D3 D D D NL
#define D4 D D D D NL
#define S "%s"
main()
{ int a,b,c,d;
char string[] = "CHINA";
a = 1; b = 2; c = 3; d = 4;
PR(D1,a);
PR(D2,a,b);
PR(D3,a,b,c);
PR(D4,a,b,c,d);
PR(S,string);
}
输出结果,
8.2 文件包含( #include)
文件包含命令的一般格式是:
#include "文件名 "
作用:预处理时,把, 文件名, 指定的文件内容复制到本文件,再对合并后的文件进行
编译。
例、
在 file1.c文件中,有文件包含命令 #include "file2.c",预处理时,先把
file2.c的内容复制到文件 file1.c,再对 file1.c进行编译。
从理论上说,#include命令可以包含任何类型的文件,只要这些文件的内容被扩
展后符合 C语言语法。
一般 #include命令用于包含扩展名为,h的, 头文件,,如 stdio.h,string.h、
math.h。在这些文件中,一般定义符号常量、宏,或声明函数原型。
程序员也可以把自己定义的符号常
量、宏,或函数原型放在头文件中,
用 #include命令包含这些头文件。
( 1)文件 print_format.h
#define PR printf
#define NL "\n"
#define D "%d "
#define D1 D NL
#define D2 D D NL
#define D3 D D D NL
#define D4 D D D D NL
#define S "%s"
( 2)文件 file1.c
#include "print_format.h“
main()
{ int a,b,c,d;
char string[] = "CHINA";
a = 1; b = 2; c = 3; d = 4;
PR(D1,a);
PR(D2,a,b);
PR(D3,a,b,c);
PR(D4,a,b,c,d);
PR(S,string);
}
说明:
1、一个 include命令只能指定一个被包含文件,如果要包含 n个文件,用 n个 Include命令。
2,#include命令的文件名,可以使用两种括号。
#include "file2.h" 先在引用被包含文件的目录查找 file2.h文件,若没有,再到系统
指定的目录查找。
#include <file2.h> 仅在系统指定的目录查找文件 file2.h。
通常的编译(包括词法分析、语法分析、代码生成、代码优化)之前,先对这些命令进
行预处理,然后将预处理的结果和源程序一起再进行通常的编译处理,以得到目标代码
( OBJ文件)。
C提供的编译预处理命令
宏命令( Macro)
文件包含命令( include)
条件编译命令
这些命令均以 #开头,以区别于语句。
宏( Macro)
一、不带参数的宏
一般形式,#define 标识符 字符串
如,#define PI 3.1415926
作用:用标识符(称为, 宏名, ) PI代替字符串, 3.1415926”。
在预编译时,将源程序中出现的宏名 PI替换为字符串, 3.1415926”,这一替换过程称为
,宏展开, 。
#define:宏定义命令
#undef:终止宏定义命令
[例 ]
#define PI 3.1415926
main()
{
float l,s,r,v;
printf("input radius:");
scanf("%f",&r); /* 输入圆的半径 */
l = 2.0*PI*r; /* 圆周长 */
s = PI*r*r; /* 圆面积 */
v = 4.0/3.0*PI*r*r*r; /* 球体积 */
printf("l=%10.4f\ns=%10.4f\nv=%10.4f\n",l,s,v);
}
关于宏定义的说明:
1、一般宏名用大写字母表示。(变量名一般用小写字母)。
2、使用宏可以提高程序的可读性和可移植性。如上述程序中,多处需要使用 π
值,用宏名既便于修改又意义明确。
3、宏定义是用宏名代替 字符串,宏扩展时仅作简单替换,不检查语法。语法检
查在编译时进行。
4、宏定义不是 C语句,后面不能有分号。如果加入分号,则连分号一起替换。
如:
#define PI 3.1415926;
area = P*r*r;
在宏扩展后成为:
area = 3.1315926; *r*r;
结果,在编译时出现语法错误。
5、通常把 #define命令放在一个文件的开头,使其在本文件全部有效。
( #define定义的宏仅在本文件有效,在其它文件中无效,这与全局变量不同)。
6、宏定义终止命令 #undef结束先前定义的宏名。
#define G 9.8
main()
{
}
#undef G /* 取消 G的意义 */
f1()
┆
7、宏定义中可以引用已定义的宏名。
[例 8.2]
#define R 3.0
#define PI 3.1415926
#deinfe L 2*PI*R
#define S PI*R*R
main()
{
printf("L=%f\nS=%f\n",L,S);
}
8、对程序中用双引号括起来的字符串,即使与宏名相同,也不替换。例如上例
的 printf语句中,双引号括起来 L和 S不被替换。
二、带参数的宏
一般形式:
#define 宏名(参数表) 字符串
带参数的宏在展开时,不是进行简单的字符串替换,而是进行参数替换。例、
[例 ]
#define PI 3.1415926
#define S(r) PI*r*r
main()
{ float a,area;
a = 3.6;
area = S(a);
printf("r=%f\narea=%f\n",a,area);
}
说明:
带参数的宏展开时,用实参字符串替换形参字符串,注意可能发生的错误。
比较好的办法是宏定义的形参加括号。
[例 ] 返回多个值的宏定义。
#define PI 3.1415926
#define CIRCLE(R,L,S,V) L=2*PI*R; S=PI*R*R; V=4/3*PI*R*R*R
main()
{ float r,l,s,v; /*半径、圆周长、圆面积、球体积 */
scanf("%f",&r);
CIRCLE(r,l,s,v);
printf("r=%6.2f,l=%6.2f,s=%6.2f,v=%6.2f\n",r,l,s,v);
}
输出结果,
[例 ] 输出格式定义为宏
#define PR printf
#define NL "\n"
#define D "%d "
#define D1 D NL
#define D2 D D NL
#define D3 D D D NL
#define D4 D D D D NL
#define S "%s"
main()
{ int a,b,c,d;
char string[] = "CHINA";
a = 1; b = 2; c = 3; d = 4;
PR(D1,a);
PR(D2,a,b);
PR(D3,a,b,c);
PR(D4,a,b,c,d);
PR(S,string);
}
输出结果,
8.2 文件包含( #include)
文件包含命令的一般格式是:
#include "文件名 "
作用:预处理时,把, 文件名, 指定的文件内容复制到本文件,再对合并后的文件进行
编译。
例、
在 file1.c文件中,有文件包含命令 #include "file2.c",预处理时,先把
file2.c的内容复制到文件 file1.c,再对 file1.c进行编译。
从理论上说,#include命令可以包含任何类型的文件,只要这些文件的内容被扩
展后符合 C语言语法。
一般 #include命令用于包含扩展名为,h的, 头文件,,如 stdio.h,string.h、
math.h。在这些文件中,一般定义符号常量、宏,或声明函数原型。
程序员也可以把自己定义的符号常
量、宏,或函数原型放在头文件中,
用 #include命令包含这些头文件。
( 1)文件 print_format.h
#define PR printf
#define NL "\n"
#define D "%d "
#define D1 D NL
#define D2 D D NL
#define D3 D D D NL
#define D4 D D D D NL
#define S "%s"
( 2)文件 file1.c
#include "print_format.h“
main()
{ int a,b,c,d;
char string[] = "CHINA";
a = 1; b = 2; c = 3; d = 4;
PR(D1,a);
PR(D2,a,b);
PR(D3,a,b,c);
PR(D4,a,b,c,d);
PR(S,string);
}
说明:
1、一个 include命令只能指定一个被包含文件,如果要包含 n个文件,用 n个 Include命令。
2,#include命令的文件名,可以使用两种括号。
#include "file2.h" 先在引用被包含文件的目录查找 file2.h文件,若没有,再到系统
指定的目录查找。
#include <file2.h> 仅在系统指定的目录查找文件 file2.h。