重庆工学院计算机科学与工程学院基础系9
第九章编译预处理第九章 编译预处理
2009年 7月 27日星期一2 重庆工学院计算机科学与工程学院 基础系
◆ 宏定义 ◆ 文件包含 ◆ 条件编译
【 编译 】 C编译系统对源程序进行:词法和语法分析,代码生成,优化 →,OBJ文件
【 编译预处理 】 编译前对源程序进行一些预加工
(改善程序设计环境 /模块化设计)
编译预处理命令均以 #开头,未尾不加分号
可出现在程序的任何位置,其作用范围:出现点至所在源程序未尾。
编译预处理第九章 编译预处理
2009年 7月 27日星期一3 重庆工学院计算机科学与工程学院 基础系预处理功能
C语言的预处理程序负责分析和处理以,#”为首字符的预处理控制行。预处理是在编译前进行的。
预处理控制行主要有:
宏替换、文件包含、条件编译和行控制等。
宏替换
define预处理命令不仅可以定义符号常量及字符串,
而且也可以定义带参数的宏。
1,简单的字符串替换一般形式
#define 宏标识符 字符串通常,宏标识符,用大写字母表示,用空格分开,末尾不带,;”,以换行符结束。
第九章 编译预处理
2009年 7月 27日星期一4 重庆工学院计算机科学与工程学院 基础系例如,
#define N 10
#define TRUE -1
#define FALSE 0
#define ON 1
#define OFF 0
#define YES 1
#define NO 0
#define PI 3.14159
#define E 2.7183
#define BLACK 0
#define BLUE 1
#define BEGIN {
#define END }
第九章 编译预处理
2009年 7月 27日星期一5 重庆工学院计算机科学与工程学院 基础系使用宏替换可增加程序的可移植型。
例如:在程序中定义显示工作摸式为 640*350,
#define XMAX 639
#define YMAM 349
当改为 1024*1024时,可定义如下:
#define XMAX 1023
#define YMAX 1023
这就增加了图形程序对硬件环境的适应性。
2,带参宏定义及宏调用与函数可带形式参数一样,宏标识符也可带有参数。
在程序中可用实参数替带形式参数,实现宏调用。
第九章 编译预处理
2009年 7月 27日星期一6 重庆工学院计算机科学与工程学院 基础系宏定义的一般格式:
#define 宏标识符 (形参数表 ) 表达式宏调用的一般形式,
宏标识符 (实参数表 )
例如,
#define MAX(a,b) (a>b)?a:b
main( )
{
int x,y;
x=10;y=20;
printf(”The maximum data is,%d”,MAX(x,y));
}
替换过程,
printf(”The maximum data is,%d”,(x>y)?x:y);
第九章 编译预处理
2009年 7月 27日星期一7 重庆工学院计算机科学与工程学院 基础系
1、宏定义格式 #define 宏名 宏体宏名和宏体均为字符串,前者必须符合标识符命名规则。预处理时在程序中用宏体替换宏名。
注意:可以用
#undef 宏名终止该宏名的作用范围。
宏定义的撤消,
#undef 宏标识符第九章 编译预处理
2009年 7月 27日星期一8 重庆工学院计算机科学与工程学院 基础系
① 定义符号常量
【 例一 】
#define M 3
#define N (M+1)
#define NN N*N/2
main()
{
clrscr();
printf("NN=%d,",NN);
printf("5*NN=%d\n",5*NN);
}
结果,NN=8,5*NN=40
【 讨论 】
如果第二行改为:
#define N M+1
结果,NN=6,5*NN=18
第九章 编译预处理
2009年 7月 27日星期一9 重庆工学院计算机科学与工程学院 基础系
② 带参数的宏定义格式 #define 宏名(参数表) 宏体
【 例二 】
#define PI 3.14159
#define s(r) PI*r*r
main()
{
float a=1,sum;
sum=s(a);
printf("r=%.0f,s=%f\n",a,sum);
}
结果:
r=1,s=3.141590
第九章 编译预处理
2009年 7月 27日星期一10 重庆工学院计算机科学与工程学院 基础系
② 带参数的宏定义
【 例三 】
#define PT 5.5
#define s(A) PT*A*A
main()
{
int a=1,b=2;
printf("%4.1f\n",s(a+b));
}
结果,9.5
【 讨论 】 注意 s(a+b)
不是函数,它不做任何计算(如果是函数,
则 s(a+b)为 s(3),结果
49.5)
s(a+b)=5.5× 1+ 2× 1+ 2=9.5
第九章 编译预处理
2009年 7月 27日星期一11 重庆工学院计算机科学与工程学院 基础系
② 带参数的宏定义
【 例四 】 选择正确答案
#include "stdio.h"
#define SUM(y) 1+y
main( )
{
int x=2;
printf("%d\n",SUM(5)*x);
}
A) 10 B) 11 C) 12 D) 15
结果,B
第九章 编译预处理
2009年 7月 27日星期一12 重庆工学院计算机科学与工程学院 基础系
2、文件包含
#include < > 标准方式只按标准方式 (系统存放 C库函数头文件所在目录 )查找所要包含的文件对 TC,默认只在 \tc\include目录下查找
#include,,
先在源文件所在目录找指定头文件,若无再按标准方式找(更保险)
功能:把给定的包含文件的内容嵌入到一个源程序文件中。
#include,文件名,或,#include <文件名 >
第九章 编译预处理
2009年 7月 27日星期一13 重庆工学院计算机科学与工程学院 基础系
#include,font.h”
A
font.h
B
A
B
file1.c file1.c
包含文件示意图特别警示文件包含 不 可以 彼此 互相 包含,否则容易造成 嵌套定义函数,
这是 C语言 不允许 的。
第九章 编译预处理
2009年 7月 27日星期一14 重庆工学院计算机科学与工程学院 基础系包含文件的存放地点,由文件路径和文件名指定,并放入双引号或尖括号中。
系统约定的查找顺序是,
双引号,源文件所在的当前文件目录?系统指定的标准目录尖括号,直接查找指定的标准目录
For example,用户在当前目录中定义有,font.h”文件,在编译程序的系统标准目录中也定义有一个同名,font.h”文件。
当用户需要使用自己定义的,font.h”文件时,
应 使用,#include,font.h” !
若 使用,#include <font.h>
将嵌入系统标准目录中的,font.h”,而不是用户自定义的头文件。
第九章 编译预处理
2009年 7月 27日星期一15 重庆工学院计算机科学与工程学院 基础系
3、条件编译
根据条件决定是否编译某一组语句。常用形式:
① 如果标识符被定义过 * 如果标识符未被定义过
#ifdef 标识符 #ifndef 标识符程序段 1 程序段 1 /*编译此程序段 */
#else #else /*#else部分可省略 */
程序段 2 程序段 2 /*反之,编译此程序段 */
#endif #endif
*此处指标识符用 #define等命令定义过 。
第九章 编译预处理
2009年 7月 27日星期一16 重庆工学院计算机科学与工程学院 基础系
② #if 表达式 /*如果表达式为真 */
程序段 1 /*编译程序段 1*/
#else
程序段 2 /否则 *编译程序段 2*/
#endif
如果用:
if 表达式程序段 1
else
程序段 2
亦可实现以上功能,但程序段 1,2均要编译。如果它们比较大,生成的 exe
文件就很大。
3、条件编译第九章 编译预处理
2009年 7月 27日星期一17 重庆工学院计算机科学与工程学院 基础系
3、条件编译【 例一 】#define DEBUG 0
main()
{
int a=10,b=20,c;
clrscr();
c=a/b;
#ifdef DEBUG
printf("a=%d,b=%d\n",a,b);
#endif
printf("c=%d\n",c);
}
结果:
a=10,b=20
c=0
【 讨论 】
如果 #define DEBUG呢?
结果不变如果没有 #define行呢?
只输出
c=0
第九章 编译预处理
2009年 7月 27日星期一18 重庆工学院计算机科学与工程学院 基础系
6、以下程序运行结果是 。
#define SQR(x) x*x
main( )
{
int a=10,k=2,m=1;
a/=SQR(k+m);
printf("%d\n",a);
}
2
3、条件编译第九章 编译预处理
2009年 7月 27日星期一19 重庆工学院计算机科学与工程学院 基础系
③ #ifndef 条件编译一般形式,
#ifndef 标识符 /*如果表达式为真 */
程序段 1 /*编译程序段 1*/
#else
程序段 2 /否则 *编译程序段 2*/
#endif
作用是,如果标识符未被定义,则编译程序段 1,
否则编译程序段 2。
例如:
3 条件编译第九章 编译预处理
2009年 7月 27日星期一20 重庆工学院计算机科学与工程学院 基础系
#define USA 1
main( )
{
#ifdef USA
printf(”currency is dollar\n”);
#else
printf(”currency is pound\n”);
#ifndef FRANCE
printf(”franc can’t be used\n”);
#endif
}
运行结果,
currency is dollar
franc can’t be used
第九章 编译预处理
2009年 7月 27日星期一21 重庆工学院计算机科学与工程学院 基础系
1,C语言的 预处理功能 是由预处理程序实现的 。 预处理命令行都要以,#”开始,可以出现在源程序文件中的任何地方,通常把宏定义和文件包含 放在 文件的 开头 。
2,宏定义中的简单字符串替换用于定义符号常量,带参数宏定义与宏调用与函数定义和函数调用类似 。 但宏的参数不存在数据类型,可适用于任何类型参数 。 包含文件是使用 #include将要包含的文件插入该命令行的相应位置处 。 被包含的文件名必须用 双引号 或 尖括号 括起来 。 条件编译 是按条件 (分别按表达式值,标识符是否被定义,标识符是否未被定义 三种情况 )有选择地编译某个程序段 。
小结:
第九章编译预处理第九章 编译预处理
2009年 7月 27日星期一2 重庆工学院计算机科学与工程学院 基础系
◆ 宏定义 ◆ 文件包含 ◆ 条件编译
【 编译 】 C编译系统对源程序进行:词法和语法分析,代码生成,优化 →,OBJ文件
【 编译预处理 】 编译前对源程序进行一些预加工
(改善程序设计环境 /模块化设计)
编译预处理命令均以 #开头,未尾不加分号
可出现在程序的任何位置,其作用范围:出现点至所在源程序未尾。
编译预处理第九章 编译预处理
2009年 7月 27日星期一3 重庆工学院计算机科学与工程学院 基础系预处理功能
C语言的预处理程序负责分析和处理以,#”为首字符的预处理控制行。预处理是在编译前进行的。
预处理控制行主要有:
宏替换、文件包含、条件编译和行控制等。
宏替换
define预处理命令不仅可以定义符号常量及字符串,
而且也可以定义带参数的宏。
1,简单的字符串替换一般形式
#define 宏标识符 字符串通常,宏标识符,用大写字母表示,用空格分开,末尾不带,;”,以换行符结束。
第九章 编译预处理
2009年 7月 27日星期一4 重庆工学院计算机科学与工程学院 基础系例如,
#define N 10
#define TRUE -1
#define FALSE 0
#define ON 1
#define OFF 0
#define YES 1
#define NO 0
#define PI 3.14159
#define E 2.7183
#define BLACK 0
#define BLUE 1
#define BEGIN {
#define END }
第九章 编译预处理
2009年 7月 27日星期一5 重庆工学院计算机科学与工程学院 基础系使用宏替换可增加程序的可移植型。
例如:在程序中定义显示工作摸式为 640*350,
#define XMAX 639
#define YMAM 349
当改为 1024*1024时,可定义如下:
#define XMAX 1023
#define YMAX 1023
这就增加了图形程序对硬件环境的适应性。
2,带参宏定义及宏调用与函数可带形式参数一样,宏标识符也可带有参数。
在程序中可用实参数替带形式参数,实现宏调用。
第九章 编译预处理
2009年 7月 27日星期一6 重庆工学院计算机科学与工程学院 基础系宏定义的一般格式:
#define 宏标识符 (形参数表 ) 表达式宏调用的一般形式,
宏标识符 (实参数表 )
例如,
#define MAX(a,b) (a>b)?a:b
main( )
{
int x,y;
x=10;y=20;
printf(”The maximum data is,%d”,MAX(x,y));
}
替换过程,
printf(”The maximum data is,%d”,(x>y)?x:y);
第九章 编译预处理
2009年 7月 27日星期一7 重庆工学院计算机科学与工程学院 基础系
1、宏定义格式 #define 宏名 宏体宏名和宏体均为字符串,前者必须符合标识符命名规则。预处理时在程序中用宏体替换宏名。
注意:可以用
#undef 宏名终止该宏名的作用范围。
宏定义的撤消,
#undef 宏标识符第九章 编译预处理
2009年 7月 27日星期一8 重庆工学院计算机科学与工程学院 基础系
① 定义符号常量
【 例一 】
#define M 3
#define N (M+1)
#define NN N*N/2
main()
{
clrscr();
printf("NN=%d,",NN);
printf("5*NN=%d\n",5*NN);
}
结果,NN=8,5*NN=40
【 讨论 】
如果第二行改为:
#define N M+1
结果,NN=6,5*NN=18
第九章 编译预处理
2009年 7月 27日星期一9 重庆工学院计算机科学与工程学院 基础系
② 带参数的宏定义格式 #define 宏名(参数表) 宏体
【 例二 】
#define PI 3.14159
#define s(r) PI*r*r
main()
{
float a=1,sum;
sum=s(a);
printf("r=%.0f,s=%f\n",a,sum);
}
结果:
r=1,s=3.141590
第九章 编译预处理
2009年 7月 27日星期一10 重庆工学院计算机科学与工程学院 基础系
② 带参数的宏定义
【 例三 】
#define PT 5.5
#define s(A) PT*A*A
main()
{
int a=1,b=2;
printf("%4.1f\n",s(a+b));
}
结果,9.5
【 讨论 】 注意 s(a+b)
不是函数,它不做任何计算(如果是函数,
则 s(a+b)为 s(3),结果
49.5)
s(a+b)=5.5× 1+ 2× 1+ 2=9.5
第九章 编译预处理
2009年 7月 27日星期一11 重庆工学院计算机科学与工程学院 基础系
② 带参数的宏定义
【 例四 】 选择正确答案
#include "stdio.h"
#define SUM(y) 1+y
main( )
{
int x=2;
printf("%d\n",SUM(5)*x);
}
A) 10 B) 11 C) 12 D) 15
结果,B
第九章 编译预处理
2009年 7月 27日星期一12 重庆工学院计算机科学与工程学院 基础系
2、文件包含
#include < > 标准方式只按标准方式 (系统存放 C库函数头文件所在目录 )查找所要包含的文件对 TC,默认只在 \tc\include目录下查找
#include,,
先在源文件所在目录找指定头文件,若无再按标准方式找(更保险)
功能:把给定的包含文件的内容嵌入到一个源程序文件中。
#include,文件名,或,#include <文件名 >
第九章 编译预处理
2009年 7月 27日星期一13 重庆工学院计算机科学与工程学院 基础系
#include,font.h”
A
font.h
B
A
B
file1.c file1.c
包含文件示意图特别警示文件包含 不 可以 彼此 互相 包含,否则容易造成 嵌套定义函数,
这是 C语言 不允许 的。
第九章 编译预处理
2009年 7月 27日星期一14 重庆工学院计算机科学与工程学院 基础系包含文件的存放地点,由文件路径和文件名指定,并放入双引号或尖括号中。
系统约定的查找顺序是,
双引号,源文件所在的当前文件目录?系统指定的标准目录尖括号,直接查找指定的标准目录
For example,用户在当前目录中定义有,font.h”文件,在编译程序的系统标准目录中也定义有一个同名,font.h”文件。
当用户需要使用自己定义的,font.h”文件时,
应 使用,#include,font.h” !
若 使用,#include <font.h>
将嵌入系统标准目录中的,font.h”,而不是用户自定义的头文件。
第九章 编译预处理
2009年 7月 27日星期一15 重庆工学院计算机科学与工程学院 基础系
3、条件编译
根据条件决定是否编译某一组语句。常用形式:
① 如果标识符被定义过 * 如果标识符未被定义过
#ifdef 标识符 #ifndef 标识符程序段 1 程序段 1 /*编译此程序段 */
#else #else /*#else部分可省略 */
程序段 2 程序段 2 /*反之,编译此程序段 */
#endif #endif
*此处指标识符用 #define等命令定义过 。
第九章 编译预处理
2009年 7月 27日星期一16 重庆工学院计算机科学与工程学院 基础系
② #if 表达式 /*如果表达式为真 */
程序段 1 /*编译程序段 1*/
#else
程序段 2 /否则 *编译程序段 2*/
#endif
如果用:
if 表达式程序段 1
else
程序段 2
亦可实现以上功能,但程序段 1,2均要编译。如果它们比较大,生成的 exe
文件就很大。
3、条件编译第九章 编译预处理
2009年 7月 27日星期一17 重庆工学院计算机科学与工程学院 基础系
3、条件编译【 例一 】#define DEBUG 0
main()
{
int a=10,b=20,c;
clrscr();
c=a/b;
#ifdef DEBUG
printf("a=%d,b=%d\n",a,b);
#endif
printf("c=%d\n",c);
}
结果:
a=10,b=20
c=0
【 讨论 】
如果 #define DEBUG呢?
结果不变如果没有 #define行呢?
只输出
c=0
第九章 编译预处理
2009年 7月 27日星期一18 重庆工学院计算机科学与工程学院 基础系
6、以下程序运行结果是 。
#define SQR(x) x*x
main( )
{
int a=10,k=2,m=1;
a/=SQR(k+m);
printf("%d\n",a);
}
2
3、条件编译第九章 编译预处理
2009年 7月 27日星期一19 重庆工学院计算机科学与工程学院 基础系
③ #ifndef 条件编译一般形式,
#ifndef 标识符 /*如果表达式为真 */
程序段 1 /*编译程序段 1*/
#else
程序段 2 /否则 *编译程序段 2*/
#endif
作用是,如果标识符未被定义,则编译程序段 1,
否则编译程序段 2。
例如:
3 条件编译第九章 编译预处理
2009年 7月 27日星期一20 重庆工学院计算机科学与工程学院 基础系
#define USA 1
main( )
{
#ifdef USA
printf(”currency is dollar\n”);
#else
printf(”currency is pound\n”);
#ifndef FRANCE
printf(”franc can’t be used\n”);
#endif
}
运行结果,
currency is dollar
franc can’t be used
第九章 编译预处理
2009年 7月 27日星期一21 重庆工学院计算机科学与工程学院 基础系
1,C语言的 预处理功能 是由预处理程序实现的 。 预处理命令行都要以,#”开始,可以出现在源程序文件中的任何地方,通常把宏定义和文件包含 放在 文件的 开头 。
2,宏定义中的简单字符串替换用于定义符号常量,带参数宏定义与宏调用与函数定义和函数调用类似 。 但宏的参数不存在数据类型,可适用于任何类型参数 。 包含文件是使用 #include将要包含的文件插入该命令行的相应位置处 。 被包含的文件名必须用 双引号 或 尖括号 括起来 。 条件编译 是按条件 (分别按表达式值,标识符是否被定义,标识符是否未被定义 三种情况 )有选择地编译某个程序段 。
小结: