第九章 编译预处理
第九章 编译预处理.
带参的宏与函数区别
带参宏 处理时间
参数类型 处理过程 编译时
函数 程序运行时
定义实参,形参类型
无类型问题
ห้องสมุดไป่ตู้
不分配内存 分配内存 简单的字符置换 先求实参值,再代入形参
程序长度
运行速度
变长
不占运行时间
不变 调用和返回占时间
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.使用说明 .
C语言程序设计 第3版 第9章 编译预处理
#include "test2.c" static int sum(int n) {
int i,s=0; for(i=1;i<=n;i++)
s=s+fact(i); return s; }
static int fact(int n) {
C语言程序设计
第9章 编译预处理
第1讲:编译预处理基本形式
提纲
1.宏定义 2.文件包含 3.条件编译
1.宏定义
不带参数宏定义 带参数宏定义
格式:
#define 标识符 字符串
功能:
指定标识符代替一个较复杂的字符串。
注意说明:
(1)宏名一般习惯用大写字母,例如宏名PI。 (2)宏名用做代替一个字符串,不作语法检查。 (3)宏定义无需在末尾加“;” (4)宏定义的有效范围为#undef命令终止。 (5)在进行宏定义时,可以引用已定义的宏名。
char web[50]; int i=0; gets(web); while(web[i]!='\0') {
#if(R==1) if(web[i]>='A'&&web[i]<='Z') {web[i]=web[i]+32; i++;}
#else if(web[i]>='a'&&web[i]<='z') {web[i]=web[i]-32; i++;}
形式3:
#ifndef 标识符 程序段1
#else 程序段2
第9章编译预处理
9.5 本章小结
宏定义是用一个标识符来表示一个字符串, 宏定义是用一个标识符来表示一个字符串, 这个字符串可以是常量、变量或表达式。 这个字符串可以是常量、变量或表达式。在宏 替换时用该字符串代换宏名。 替换时用该字符串代换宏名。宏定义可以带有 参数,宏替换时是以实参代换形参, 参数,宏替换时是以实参代换形参,而不是 值传送” 为了避免宏替换时发生错误, “值传送”。为了避免宏替换时发生错误,宏 定义中的字符串应加括号。 定义中的字符串应加括号。 文件包含是指一个源文件可以将另一个源 文件包含进来, 文件包含进来,它可用来把多个源文件连接成 一个源文件进行编译,生成一个目标文件。 一个源文件进行编译,生成一个目标文件。使 用标准库函数时,要注意将其头文件包含进来。 用标准库函数时,要注意将其头文件包含进来。
#define MAX(x,y) (x>y)?x:y main() { int a,b,max; printf("Please Input a ,b: "); scanf("%d%d",&a,&b); max=MAX(a,b); printf("Max=%d\n",max); } 程序运行结果: Please Input a ,b: 10 20 Max=20
例9.1宏定义的使用 宏定义的使用
#define NAME "Welcome to use C." /* NAME 是宏名 */ main() { printf(NAME); } 程序运行结果: Welcome to use C.
使用宏定义的说明: 使用宏定义的说明:
(1) 宏名一般用大写字母表示,变量名通常用小写字 母表示,但并非是规定。 母表示 但并非是规定。 (2) 宏展开时将宏名替换为字符串,可以是常数,也 可以是表达式,预处理程序对它不作任何检查。 (3) 宏定义不是语句,在行末不必加分号,如加上分 号则连分号也一起替换。 4)在宏定义和宏替换时,可以使用已经定义的宏名。 )在宏定义和宏替换时,可以使用已经定义的宏名。
第9章 编译预处理
C/C++程序设计第9 章编译预处理计算机学院C/C++程序设计课程组C/C++程序设计第1 章主要内容C语言有三种预处理命令,分别是宏定义、文件包含和条件编译。
本章主要介绍宏定义与引用、文件包含处理和条件编译命令。
C/C++程序设计9.1 宏定义所谓“宏”就是将一个标识符定义成一个字符串符,完成定义的命令称为“宏定义”或预处理命令,其中,“标识符”称为“宏名”;当定义了宏名后,在源程序中就可以“引用宏”。
带有宏的程序,源程序开始编译前,系统将会把源程序清单中所引用的宏名替换成对应的一串字符,然后再编译源程序。
替换的过程称为“宏替换”,也称为“宏展开”。
9.1.1 不带参数的宏定义#define 宏名字符串关于宏定义注意以下几点:(1)字符串不带双引号。
(2)宏名的前后应有空格,以便准确的辨认宏名。
(3)C预处理命令都是以换行符(\n)结尾的,即每条C预处理命令都占用一行;本命令不是语句,其后不要跟分号(;)。
(4)在字符串中如果出现运算符,要注意替换后的结果,通常可以在合适的位置上加括号。
C/C++程序设计【例9.1】求园的周长、面积和球的体积。
#include <stdio.h>#define PI 3.14159//定义宏名PI为3.14159 void main( ) {float l,s,r,v;printf("input redius:\n" );scanf("%f",&r);l=2.0*PI*r;s=P I*r*r;v=3.0/4*PI*r*r*r; // 宏展开后为:v=3.0/4*3.14159*r*r*r printf("l=%10.4f\ns=%10.4f\nv=%10.4f\n",l,s,v);}(5) 宏定义也有定义域,它的定义域是从开始定义处到本程序文件的结尾。
所以一般都将宏定义放在源程序开头。
第09章_编译预处理
主要内容
9.1 编译预处理 9.2 宏定义 9.3 文件包含
9.1 编译预处理
一、定义 预处理是由一组命令组成的,这些命令在程 序正常编译之前被执行。 二、常用的预处理命令 1、宏定义命令 2、文件包含命令
三、预处理命令特点 • 编译预处理:在编译源程序之前根据预处理命 令对源程序进行的预加工,由编译系统中的预 处理程序完成。 • 格式:以符号 “ # ” 开头 如:#include <math.h> • 位置:宏定义与文件包含命令一般放在程序的 开头(原则上可以放在程序中的任意位置) • 作用域:从定义起直到其所在源程序的末尾。 • 使用预处理命令的好处: 改进程序设计环境,提高编程效率、易读、易改
带参宏定义的一般形式: #define 宏名(参数表) 宏体 预处理时进行如下宏替换: 用宏体替换宏名的同时,用实参分别替换 形参,而不是用实参的值,即替换时不进 行任何计算。 本例中的语句: t=MAX(x , y); 若理解为:t=(10>20)?(10): (20);
则错。
• 特别提示: • 使用带参宏定义时,宏体中的参数要用括号 扩起来,以保证替换后不影响原来的运算顺 序。
9.3 文件包含
• 文件包含是实现结构化程序设计的重要手 段之一。 • 定义: 文件包含是指用#include 命令将另一指定的 源文件包含进当前源程序文件中#include 命 令所处的位置,共同组成一个程序文件,然 后对合并后的源文件进行编译、连接,生成 一个目标文件。
9.3 文件包含
文件包含命令的一般形式有两种:
下图给出了文件包含命令的预处理过程。
• 例1 对任意整数开平方的主程序文件 : #include <stdio.h> #include "math.h" void main( ) { double a=10; printf(“%lf”, sqrt(a)); } • 预处理后,头文件stdio.h和math.h中的内容 即插入到当前文件的#include 命令处,实现 源文件的组合。
第9章 编译预处理.
编译预处理
一、编译预处理的概念 二、宏定义 三、文件包含 四、条件编译
一、编译预处理的概念
ANSI C标准规定可以在C源程序中加入一些“预 处理命令”(preprocessor DireCtiveS) ,以改进程序设 计环境,提高编程效率。这些预处理命令是由ANSI C 统一规定的,但是它不是C语言本身的组成部分,不 能直接对它们进行编译(因为编译程序不能识别它们)。 必须在对程序进行通常的编译(包括词法和语法分析、 代码生成、优化等)之前,先对程序中这些特殊的命令 进行“预处理”。 C语言与其他高级语言的一个重要区别是可以使用 预处理命令和具有预处理的功能。
2、带参数的宏定义
不是进行简单的字符串替换,还要进行参数替换。 其定义的一般形式为 #define 宏名(参数表) 字符串
字符串对应括弧中参数。 例:#define s(a,b这里,3对应a,2对应b
说明: (1)对带参数的宏的展开只是将语句中的宏名后面 括号内的实参字符串代替#define命令行中的 形参。 (2) 在宏定义时,在宏名与带参数的括弧之间不 应加空格,否则将空格以后的字符都作为替代 字符串的一部分。
(4) 在#inClude命令中,文件名可以用双引号或尖括 号括起来,如可以在file1.C中用 #inClude <file2.h> 或#inClude "file2.h"都是合法的。 (5) 被包含文件(file2.h)与其所在的文件(即用 #inClude命令的源文件file1.C),在预编译后已成为 同一个文件(而不是两个文件)。
这种方法使用户能以一个简单的名字代替一 个长的字符串,因此把这个标识符(名字)称为 “宏名”,在预编译时将宏名替换成字符串的过 程称为“宏展开”。#define是宏定义命令。
第9章 编译预处理
宏定义
(二)
宏提供了一种文本替换机制,可分为两类: 不带参数的宏和带参数的宏。
2、带参数的宏定义是指在宏名后面跟有形参表,在替换时,仅用 3、预处理命令#undef 实参替换宏体中与形参表中相同的标识符,宏体中其余部分不变。 #undef与#define命令相对应,是取消宏定义的命令。 #undef #define 其定义格式: 格式如下: #define <宏名>(<参数表>) <宏体> #undef <宏名> 调用带参数的宏: 宏定义的生存期是以定义时起,到被取消时为止。 例如,#define 宏名[空格](实参表) 如果始终没有被取消,则到该文件结束为止。 SQ(x) x*x
1、一条文件包含命令只能包含一个文件,如要包含多个文件须用多条 、一条文件包含命令只能包含一个文件, 文件包含命令。 文件包含命令。 2、文件包含可以嵌套,即被包含文件中还可以包含其他文件。 、文件包含可以嵌套,即被包含文件中还可以包含其他文件。 3、被包含的文件应当是源文件,且当被包含文件的内容发生改变时, 、被包含的文件应当是源文件,且当被包含文件的内容发生改变时, 包含这个源文件的所有源文件都应该重新进行编译
带参宏与函数的差异:见书P173
事实上在C++中带参宏的优越性已被 内联函数所替代。
语句 s=SQ(a+b); 将被替换为:s=a+b*a+b; 若是,#define SQ(x) (x)*(x) 则上述语句将被替换为: s=(a+b)*(a+b);
练习
3 0 下面程序执行FOR循环时,j的初值是__,终值是__,运行 结果是_________。 #include <iostream.h> #define BOT (-2) #define TOP (BOT+5) #define PRI(arg) printf(“%d\n”,arg) #define FOR(arg) for (;(arg);(arg)--) void main() int i=(-2),j=((-2)+5); { int i=BOT,j=TOP; FOR(j) for (;(j);(j)--) switch(j) ③j=1 { case 1: PRI(i++); -2 case 2: PRI(j);break; ②j=2 default: PRI(i); 2 ①j=3 } -2 } 1
第九章 编译预处理
(3)如果文件file1.h中包含文件file2.h,而文件 file2.h要用到文件file3.h的内容,则可在文件 file1.h中用两个include命令分别包含文件file2.h和 文件file3.h,而且文件file3.h应出现在文件file2.h 之前,即在文件file1.h中: #include "file3.h" #include "file2.h"
9.2 宏定义
9.2.1不带参数的宏定义
C语言源程序中允许用一个标识符来表示一个较复杂的字 符串,称为“宏”,被定义为“宏”的标识符称为“宏名”。 在编译预处理时,对程序中所有出现的“宏名”,都用宏定 义中的字符串去代换,这称为“宏代换”或“宏展开”。
语法形式: #define 标识符 字符串
#define为预编译符。 标识符称为“宏名”,通常使用大写英文字母和有直观 意义的标识符命名,以区别于源程序中的其它标识符。 字符串可以是常数、表达式、格式串等。
【例 R 1 main() { float c,r,s; printf("输入圆的半径或矩形的边长:"); scanf("%f",&c); #ifdef R r=3.14*c*c; printf("圆面积=%f\n",r); #else s=c*c; printf("矩形面积=%f\n",s); #endif }
9.2.2
带参数的宏定义
1.带参数宏的定义与调用
定义形式: #define 标识符(形式参数表)字符串 ◆形式参数称为宏名的形式参数,简称形参; ◆构成宏体的字符串中应该包含所指的形式参数; ◆宏名与后续圆括号之间不能留空格。 ◆带参数宏调用的一般形式为 宏名(实参表); 例如,宏定义与调用形式如下: #define M(y) y*y+3*y k=M(5); /*宏定义*/ /*宏调用*/
第9章 编译预处理
一,编译预处理的概念 二,宏定义 三,文件包含 四,条件编译
一,编译预处理的概念
ANSI C标准规定可以在 源程序中加入一些"预 标准规定可以在C源程序中加入一些 标准规定可以在 源程序中加入一些" 处理命令"(preprocessor DireCtiveS) ,以改进程序设 处理命令" 计环境,提高编程效率.这些预处理命令是由ANSI C 计环境,提高编程效率.这些预处理命令是由 统一规定的,但是它不是C语言本身的组成部分 语言本身的组成部分, 统一规定的,但是它不是 语言本身的组成部分,不 能直接对它们进行编译(因为编译程序不能识别它们 因为编译程序不能识别它们). 能直接对它们进行编译(因为编译程序不能识别它们). 必须在对程序进行通常的编译(包括词法和语法分析 包括词法和语法分析, 必须在对程序进行通常的编译 包括词法和语法分析, 代码生成,优化等)之前,先对程序中这些特殊的命令 代码生成,优化等 之前, 之前 进行"预处理" 进行"预处理". C语言与其他高级语言的一个重要区别是可以使用 语言与其他高级语言的一个重要区别是可以使用 预处理命令和具有预处理的功能. 预处理命令和具有预处理的功能.
(4) 在#inClude命令中,文件名可以用双引号或尖括 命令中, 命令中 号括起来,如可以在file1.C中用 #inClude <file2.h> 号括起来,如可以在 中用 都是合法的. 或#inClude "file2.h"都是合法的. 都是合法的 (5) 被包含文件 被包含文件(file2.h)与其所在的文件 即用 与其所在的文件(即用 与其所在的文件 #inClude命令的源文件 命令的源文件file1.C),在预编译后已成为 命令的源文件 , 同一个文件(而不是两个文件 而不是两个文件). 同一个文件 而不是两个文件 .
- 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。