第九章 编译预处理
第九章 编译预处理.

带参的宏与函数区别
带参宏 处理时间
参数类型 处理过程 编译时
函数 程序运行时
定义实参,形参类型
无类型问题
ห้องสมุดไป่ตู้
不分配内存 分配内存 简单的字符置换 先求实参值,再代入形参
程序长度
运行速度
变长
不占运行时间
不变 调用和返回占时间
9.2 文件包含
一、“文件包含”
通过命令#include把已经进入系统的另一个文件的
• 一般形式: #define 宏名 [宏体] • 功能:用指定标识符 (宏名)代替字符序列 (宏 例 #define YES 1 体) main()
printf(“2* PI=%f\n”,PI*2); 展开后: if(x==1 ) var=LENGTH*2; printf(“correct! \n”); 宏展开: printf(“2* 3.14159*2); else if (x==0 ) printf(“error! \n”); n”, 宏展开: var=PI=%f\ 80+40 *2;
预编译时,用被包含文件的内容取代该预处理命令, 再对“包含”后的文件作一个源文件编译
整个内容嵌入进来。它实际上是宏替换的延伸。
在C语言开发程序时,我们可把一些宏定义按照功
能分别存入不同的文件中,当我们需要使用某类宏定
义时,就无须在程序中重新定义,而只要把这些宏定
义所在的文件,包含在程序的开头就行了。
二、两种格式:
1、 #include “文件标识”
“文件标识”中包含有文件路径。按这种格式定 义
宏体可缺省,表示宏名 9.1 宏 定 义
一、不带参数宏定义
定义过或取消宏体
如
定义位置 (一般在函数外面 如 :任意 #define YES 1 ) { …….. YES原作用域 作用域:从定义命令到文件结束 #define NO} 0 例 #define PI WIDTH 80 #undef可终止宏名作用域 #define 3.1415926 #undef YES ( #define 宏名 LENGTH WIDTH+40 格式: #define #undef OUT printf(“Hello,World”); #define YES ) 0 var=LENGTH*2; 宏展开:预编译时,用宏体替换宏名 ---不作语法检查 YES新作用域 ( max() ) 宏展开:var= {…….. 80+40 *2; 引号中的内容与宏名相同也不置换 } 例 #define WIDTH 80 宏定义可嵌套,不能递归 if(x==YES) printf(“correct!\n”); 宏定义中使用必要的括号() #define MAX ( ) #define LENGTH WIDTH+40 例 #define PI MAX+10 3.14159 else if 例 (x==NO ) printf(“error! \n”);
第九章编译预处理

第九章 编译预处理编译指令(编译预处理指令):C 源程序除了包含程序命令(语句)外,还可以使用各种编译指令(编译预处理指令)。
编译指令(编译预处理指令)是给编译器的工作指令。
这些编译指令通知编译器在编译工作开始之前对源程序进行某些处理。
编译指令都是用“#”引导。
编译预处理:编译前根据编译预处理指令对源程序的一些处理工作。
C 语言编译预处理主要包括宏定义、文件包含、条件编译。
编译工作实际分为两个阶段:编译预处理、编译。
广义的编译工作还包括连接。
9、1 宏定义宏定义:用标识符来代表一个字符串(给字符串取个名字)。
C 语言用“#define ”进行宏定义。
C 编译系统在编译前将这些标识符替换成所定义的字符串。
宏定义分为不带参数的宏定义和带参数宏定义。
9、1、1 不带参数宏定义(简单替换)1其中:标识符-宏名。
2、宏调用:在程序中用宏名替代字符串。
3、宏展开:编译预处理时将字符串替换宏名的过程,称为宏展开。
说明:(1)宏名遵循标识符规定,习惯用大写字母表示,以便区别普通的变量。
(2)#define之间不留空格,宏名两侧空格(至少一个)分隔。
(3)宏定义字符串不要以分号结束,否则分号也作为字符串的一部分参加展开。
从这点上看宏展开实际上是简单的替换。
例如:#define PI 3.14; 展开为s=3.14;*r*r ;(导致编译错误)(4)宏定义用宏名代替一个字符串,并不管它的数据类型是什么,也不管宏展开后的词法和语法的正确性,只是简单的替换。
是否正确,编译时由编译器判断。
例如:#define PI 3.I4 照样进行宏展开(替换),是否正确,由编译器来判断。
(5)#define 宏定义宏名的作用范围从定义命令开始直到本源程序文件结束。
可以通过#undef 终止宏名的作用域。
(6)宏定义中,可以出现已经定义的宏名,还可以层层置换。
(7)宏名出现在双引号“”括起来的字符串中时,将不会产生宏替换。
(因为出现在字符串中的任何字符都作为字符串的组成部分)(8)宏定义是预处理指令,与定义变量不同,它只是进行简单的字符串替换,不分配内存。
c语言第9章编译预处理

第9章编译预处理本章要求:1、熟悉宏定义与宏扩展。
a宏与函数的区别。
2、熟悉文件包含命令#include的作用及其预处理方法。
3、熟悉条件编译的使用。
概述编译预处理:在源程序文件中,加入“编译预处理命令”,使编译程序在对源程序进行通常的编译(包括词法分析、语法分析、代码生成、代码优化)之前,先对这些命令进行预处理,然后将预处理的结果和源程序一起再进行通常的编译处理,以得到目标代码(OBJ文件)。
C提供的编译预处理命令:宏命令(Macro)、文件包含命令(include)、条件编译命令这些命令均以#开头,以区别于语句。
9.1 宏定义(Macro)一、不带参数的宏一般形式: #define 标识符字符串如: #define PI 3.1415926作用:用标识符(称为“宏名”)PI代替字符串“3.1415926”。
在预编译时,将源程序中出现的宏名PI替换为字符串“3.1415926”,这一替换过程称为“宏展开”。
#define:宏定义命令#undef:终止宏定义命令[例9.1]#define PI 3.1415926main(){ 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、宏定义是用宏名代替字符串,宏扩展时仅作简单替换,不检查语法。
语法检查在编译时进行。
第9章 编译预处理

#include <stdio.h> #include "d:\pp.h" #define MAX 10 void main() { int n; for(n=1;n<=MAX;n++) printf("%2d, %3d, %4d, %5d\n",n,sqr(n),cube(n),quad(n)); }
9.4 条件编译
概念:所谓“条件编译”,是对部分内容指定编译的条件, 使其只在满足一定条件才进行编译。
条件编译命令的几种形式: (1)#ifdef 标识符 程序段1 #else 程序段2 #endif (2)#ifndef 标识符 程序段1 #else 程序段2 #endif
(3) #if 表达式 程序段1 #else 程序段2 #endif
}
带参的宏与函数区别
带参宏 处理时间 参数类型 编译时 无类型问题
函数 程序运行时
处理过程
程序长度
定义实参,形参类型 不分配内存 分配内存 简单的字符置换 先求实参值,再代入形参 不变 变长
运行速度
不占运行时间
调用和返回占时间
9.3 文件包含
<> 直接按标准目录搜索 功能:一个源文件可将另一个源文件的内容 “” 先在当前目录搜索,再搜索标准目录 全部包含进来 可指定路径 一般形式: #include “文件名” 或 #include <文件名>
源文件(*.c) 头文件(*.h)
文件包含可嵌套
#include “file2.c” A file1.c
#include “file3.c” C B file3.c file2.c
第九章 编译预处理

说明: 说明: 1. 注意带参数的宏定义与函数的区别。 注意带参数的宏定义与函数的区别。
函数调用是在程序运行时处理的 ;宏展开是在编译 时进行的;不进行分配单元,不进行值传递, 时进行的;不进行分配单元,不进行值传递,也没 有返回值。 有返回值。 宏名无类型问题,其参数也无类型。 宏名无类型问题,其参数也无类型。
说明: 说明: 1. 宏名一般习惯用大写字母表示。 宏名一般习惯用大写字母表示。 2. 使用宏定义可以提高程序的可移植性。 使用宏定义可以提高程序的可移植性。 3. 宏定义不是C语句,后面不加分号。 语句,后面不加分号。 4. 宏定义不作语法检查,定义时要仔细。 宏定义不作语法检查,定义时要仔细。 5. 一般宏定义命令写在文件的开头,函数之前, 一般宏定义命令写在文件的开头,函数之前, 其有效范围在整个文件范围内。 其有效范围在整个文件范围内。 6. 可以用undef命令终止宏定义的作用域。 命令终止宏定义的作用域。 7. 对于放在括号内与宏名相同的字符串将不被 置换。 置换。
2. 主要提供三种处理功能: 主要提供三种处理功能:
• 宏定义 • 文件包含 • 条件编译 号开头的三种命令来实现。 分别以 # 号开头的三种命令来实现。
9.2 宏定义
9.2.1 不带参数的宏定义 用指定的标识符来表示一个字符串。 用指定的标识符来表示一个字符串。 一般格式: 一般格式:#define 标识符 字符串 例:#define PI 3.1415926 作用: 来代表“ 作用:用PI来代表“3.1415926”。以一个简单 来代表 。 的名字代替长的符号串。 的名字代替长的符号串。称这个标识符为 宏名” “宏名”,在编译时将宏名替换成字符串的 过程称为“宏展开” 过程称为“宏展开”。 #define 是宏定义命令。 是宏定义命令。
第9章 编译预处理

3、条件编译
• 根据条件决定是否编译某一组语句。常用形式:
如果标识符被定义过* ① 如果标识符被定义过* #ifdef 标识符 程序段1 程序段 #else 程序段2 程序段 #endif 如果标识符未被定义过 #ifndef 标识符 程序段1 编译此程序段 编译此程序段*/ 程序段 /*编译此程序段 #else /*#else部分可省略 部分可省略*/ 部分可省略 程序段2 反之 编译此程序段*/ 反之, 程序段 /*反之,编译此程序段 #endif
main() { clrscr(); printf("NN=%d,",NN); printf("5*NN=%d\n",5*NN); }
结果:NN=8,5*NN=40
8
②带参数的宏定义 格式 #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); }
#undef 宏标识符
7
①定义符号常量
【例一】 例一】 #define M 3 #define N (M+1) #define NN N*N/2
【讨论】 讨论】 如果第二行改为: 如果第二行改为: #define N M+1 NN: M + 1*M + 1/2 结果: 结果: NN=6,5*NN=18 5* M + 1*M + 1/2
2. 带参宏定义及宏调用
与函数可带形式参数一样,宏标识符也可带有参数。 在程序中可用实参数替带形式参数,实现宏调用。
第9章编译预处理

9.8 用条件编译方法实现以下功能:
输入一行电报文字,可以任选两种输出,一为原文输出; 一为将字母变成其下一字母(如‘a’变成‘B’……‘Z’
变成‘a’。其他字符不变)。用#define命令来控制是 否要译成密码。例如:
# define CHANGE1则输出密码。若#define CHANGE0则不译成密码,按原码输出。
以下正确的描述为( )。 A)每个C语言程序必须在开头用预处理
命令#include <stdio.h> B)预处理命令必须位于C源程序的首部 C)在C语言中预处理命令都以“#”开头 D)C语言的预处理命令只能实现宏定义
和条件编译的功能
9.1 宏定义
9.1.1 不带参数的宏定义 •一般形式:
#define 宏名 宏体 例: #define PI 3.1415926 •功能:用指定标识符(宏名)代替字符序列(宏体) •宏展开:预编译时,用宏体替换宏名---不作语法检查 #define PI 3.L4l59----正常替换
D)仅仅搜索当前目录
9.3 条件编译
条件编译命令有以下几种形式:
(1) #ifdef标识符
程序段1 #else
程序段2 #endif
#ifdef COMPUTER-A #define INTEGER-SIZE 16
#else #define INTEGER-SIZE 32
#endif
(2) #ifndef标识符 程序段1
•课时:2 •教学方法:多媒体演示 •教学过程
编译预处理命令行
作用:对源程序编译之前做一些处理 预处理功能主要有以下三种:
C语言第9章 编译预处理

[例9.2] 例
#define X(a) a*a main() { printf(“%d\n”,X(4+5)); } 程序运行的结果? 程序运行的结果? 29?81? ? ? 程序运行结果为: ,并非81 程序运行结果为:29,并非
[例9.2] 例
#define X(a) (a)*(a) main() { printf(“%d\n”,X(4+5)); } 程序运行的结果? 程序运行的结果? 程序运行结果为: 程序运行结果为:81
[Retu 一般源程序中所有的行都参加编译。 条件编译: 条件编译:程序中的一部分内容在满足一定的条件下才能 进行编译,即对一部分内容指定编译条件。 进行编译,即对一部分内容指定编译条件。 条件编译可有效地提高程序的可移植性, 条件编译可有效地提高程序的可移植性,并广泛地应用在 商业软件中,为一个程序提供各种不同的版本。 商业软件中,为一个程序提供各种不同的版本。
( 1)定义有参宏时,宏名与左圆括号之间不能留有空格。 )定义有参宏时,宏名与左圆括号之间不能留有空格。 否则, 编译系统将空格以后的所有字符均作为替代字符串, 否则,C编译系统将空格以后的所有字符均作为替代字符串, 而将该宏视为无参宏。 而将该宏视为无参宏。
( 2)有参宏的展开,只是将实参作为字符串, 简单地置换 )有参宏的展开,只是将实参作为字符串, 形参字符串,而不做任何语法检查。在定义有参宏时, 形参字符串,而不做任何语法检查。在定义有参宏时,在所 有形参外和整个字符串外,均加一对圆括号。 有形参外和整个字符串外,均加一对圆括号。
[Return]
9.2
文件包含
1.文件包含的概念 . 文件包含是指, 文件包含是指,一个源文件可以将另一个源文件的全部内容包 含进来。 含进来。 2.文件包含处理命令的格式 . 包含文件名” 包含文件名> #include “包含文件名” 或 #include <包含文件名 包含文件名 包含文件名 两种格式的区别仅在于: 两种格式的区别仅在于: ( 1)使用双引号: 系统首先到当前目录下查找被包含文件, ) 使用双引号:系统首先到当前目录下查找被包含文件, 如果没找到,再到系统指定的“包含文件目录” 如果没找到,再到系统指定的“包含文件目录”(由用户在配置环 境时设置)去查找。 境时设置)去查找。 ( 2)使用尖括号: 直接到系统指定的 “包含文件目录 ”去查 ) 使用尖括号:直接到系统指定的“包含文件目录” 一般地说,使用双引号比较保险。 找。一般地说,使用双引号比较保险。 3.文件包含的优点 . [Return] 4.使用说明 .
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第九章编译预处理
一、单选题
1.以下对宏替换的叙述不正确的是
A)宏替换只是字符的替换B)宏替换不占运行时间
C)宏名无类型,其参数也无类型
D)带参的宏替换在替换时,先求出实参表达式的值,然后代入形参运算求值2.宏定义#define PI 3.14中的宏名PI代替
A)一个单精度实数)B)一个双精度实数
C)一个字符串 D)不确定类型的数
3.有以下宏定义
#define k 2
#define X(k) ((k+1)*k)
当C程序中的语句y = 2 * (K + X(5));被执行后,
A)y中的值不确定 B)y中的值为65
C)语句报错 D)y中的值为34
4.以下程序的输出结果是
#define MIN(x, y) (x) < (y) ? (x) : (y)
main()
{ int i , j, k;
i = 10; j = 15;
k = 10 * MIN(i, j);
printf(“%d\n”, k);
}
A)15 B)100 C)10 D)150
5.以下程序中的for循环执行的次数是
#define N 2
#define M N + 1
#define NUM (M + 1) * M / 2
main()
{ int i;
for(i = 1; i <= NUM; i++);
pritnf(“%d\n”, i );
}
A)5 B)6 C)8 D)9
6.以下程序的输出结果是
#include “stdio.h”
#define FUDGF(y) 2.84 + y
#define PR(a) printf(“%d”, (int) ( a ) ) #define PRINT1(a) PR(a); putchar(‘\n’)
main()
{ int x = 2;
PRINTF1(FUDGF(5) * X);
}
A)11 B)12 C)13 D)15
7.以下程序的输出结果是
#define FMT “%d,”
main()
{
int b[][4] = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23};
printf(FMT, *(*(b+1)+1));
printfFMT, b[2][2]);
}
A)1,11, B)1,11 C)11,21, D)13,21
8.若有宏定义如下:
#define MOD(x,y) x%y
则执行以下程序段的输出为
int z, a = 15, b = 100;
z = MOD(b, a);
printf(“%d\n”, z++);
A)11 B)10 C)6 D)5
二、填空题
1.有以下宏定义和赋值语句,宏置换后的赋值语句的形式是。
#define A 3+5
……
p = A * A;
2.以下程序的输出结果是。
#define PR(ar) printf(“ar = %d“, ar)
main()
{ int j, a[] = { 1, 3, 5, 7, 9, 11, 13, 15}, *p = a + 5;
for(j = 3; j ; j--)
switch( j )
{ case 1:
case 2: PR(*p++); break;
case 3: PR(*(--p) );
}
}
3.以下程序的执行结果是。
#define DOUBLE(r) r*r
main()
{
int y1 = 1, y2 = 1, t;
t = DOUBLE(y1 + y2);
printf(“%d\n”, t);
}
4.以下程序的执行结果是。
#define PRINT(V) printf(“V = %d\t”,V)
main()
{
int a, b;
a = 1;
b = 2;
PRINT(a);
PRINT(b);
}
第九章编译预处理
一、选择题
1.【A】【B】【C】【D】 2.【A】【B】【C】【D】 3.【A】【B】【C】【D】4.【A】【B】【C】【D】 5.【A】【B】【C】【D】 6.【A】【B】【C】【D】7.【A】【B】【C】【D】 8.【A】【B】【C】【D】
二、填空题
1. p = 3+5*3+5;
2. ar = 9 ar = 9 ar = 11
3. 3
4. V = 1 V = 2。