C语言程序设计-第09章 预处理命令

合集下载

c语言学习资料第9章 预处理命令.doc

c语言学习资料第9章 预处理命令.doc

第9章预处理命令宏定义不是c语句,所以不能在行尾加分号。

如果加了分号则会连分号一起进行置换。

可以用#undef命令终止宏定义的作用域。

对程序中用""括起来的内容(即字符串内的字符),即使与宏名相同,也不进行置换。

宏定义只做字符替换,不分配内存空间。

宏名不是变量,不分配存储空间,也不能对其进行赋值。

在宏展开时,预处理程序仅对宏名作简单的字符串替换,不作任何检查。

在进行宏定义时,可以引用已定义的宏名无参宏定义的一般格式:#define 标识符字符串将这个标识符(名字)称为“宏名”,在用预编译时将宏名替换成字符串的过程称为"宏展开"。

#define是宏定义命令。

带参宏定义的一般格式:#define 宏名(形参表)字符串带参宏的调用和宏展开:调用格式:宏名(实参表);宏展开(又称为宏替换)的方法:用宏调用提供的实参直接置换宏定义中相应的形参,非形参字符保持不变。

定义有参宏时,宏名与左圆括号之间不能留有空格。

否则,C编译系统会将空格以后的所有字符均作为替代字符串,而将该宏视为无参宏。

有参宏的展开只是将实参作为字符串,简单地置换形参字符串而不做任何语法检查。

为了避免出错,可以在所有形参外,甚至整个字符串外,均加上一对圆括号。

如:#define S(r) 3.14*(r)*(r)则:areapS(a^b); 展开后为:area^ 3.14*(a^ b)*(cH- b);调用有参函数时,是先求出实参的值,然后再复制一份给形参。

而展开有参宏时,只是将实参简单地置换形参。

函数调用是在程序运行时处理的,为形参分配临时的内存单元;而宏展开则是在编译前进行的,在展开时不分配内存单元,不进行值的传递,也没有’返回值"的概念。

调用函数只可得到一个返回值,而用宏可以设法得到几个结果。

在有参函数中,形参都是有类型的,所以要求实参的类型与其一致;而在有参宏中,形参和宏名都没有类型,只是一个简单的符号代表,因此,宏定义时,字符串可以是任何类型的数据。

C语言程序设计 第9章 预处理命令

C语言程序设计 第9章 预处理命令

区别“文件名”和<文件名> --关于#include的使用
#include “文件名” #include <文件名> 带双引号的文件名, 带尖括号的文件名, 系统将先在源程序所在 系统将直接按照指定 的目录内查找指定的包 的标准方式到相关的 含文件;如果找不到, 目录中去寻找。 再按照系统指定的标准 方式到相关的目录中去 寻找。 多用于包含用户文件。 多用于标准库函数。
答案:8 20 12

5、设有以下程序,为使之正确运行,请填 入应包含的命令行。其中,tryme()函数在 a:\myfile1.c 中有定义。
#include “a:\myfile1.c” ___________________ main() { printf(“\n”); tryme(); }
9.3 条件编译
格式一: #ifdef 标识符
#ifdef 标识符
程序段1
程序段1
#else
#endif
程序段2
#endif
格式二:
格式三:
#ifndef 标识符
程序段1 #else 程序段2 #endif
#if 表达式
程序段1 #else 程序段2 #endif
课堂练习:
1、以下叙述中不正确的是: (A)预处理命令行都必须以#号开始 (B)C程序中凡是以#开始的命令行都是预处理命 令行 (C)C程序在执行过程中对预处理命令进行预处理 (D)以下是正确的宏定义 #define IBM_PC

File Edit Run Compile Project Options Debug Break/watch ╒═══════════════════════════ │ Compiler │ │ │ Linker │ │ │ Environment │ │ │ Directories │ │ ┌──────────────────── │ │ Include directories: C:\TC\INCLUDE │ │ Library directories: C:\TC\LIB │ Output directory: D:\CDATA │ │ Turbo C directory: C:\TC │ │ Pick file name: │ │ Current pick file:

第9章:预处理命令

第9章:预处理命令

7、宏定义时,可以引用已定义的宏 名,可以层层置换。
例9.2 # define R 3.0
# define PI 3.1415926 # define L 2*PI*R # define S PI*R*R main( ) {printf(“L=%f \n S=%f \n”,L,S); } printf函数展开为:
对宏定义的9点说明: 对宏定义的9点说明:
1、宏名一般习惯用大写字母表示。 2、用宏名代替一个字符串,可以减少程 序中重复书写某些字符串的工作量。当需要 改变某一个常量的值时,只改变宏定义命令 行即可。例: #define M 20 float str[M]; 3、宏定义是用宏名代替一个字符串,也 就是作简单的替换,不作正确性检查。即使 写错了,预处理时也照样带入。只有在编译 已被宏展开的源程序时才报错。
文件包含” 9.2 “文件包含”处理 文件包含
“文件包含”处理是指一个源文件可以将另 外一个源文件的全部内容包含进来。 C语言提供了#include命令,用来实现“文件 包含”的操作。一般形式为: file1.c # include “文件名” 文件名” 文件名 file1.c file2.c
# include “file2.c” A
例 9.1 p.188
# 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 * PI * r * r * r ; printf(“l=%10.4f\n s=%10.4f\n v=%10.4f\n”,l,s,v) ; }

第9章 预处理命令

第9章  预处理命令
可缺省,表示宏名 可缺省, 定义过或取消宏体
第 十 章
预 处 理 命 令
后面的单词串 容文本 #define SIZE 10 如 #define YES 1 #define INT_STR "%d" void main ( ) #define NO 0 void main ( ) { #define PI 3.1415926 { int a[10], i; a[10], 宏定义 #define OUT printf(“Hello,World”); int a[SIZE], i; a[SIZE], for (i = 0; i < 10; i++) 10; for (i = 0; i < SIZE; i++) SIZE; scanf ("%d", &a[i]); ("%d", scanf (INT_STR, &a[i]); (INT_STR, 预编译 for (i = 10 - 1; i >= 0; i--) i--) for (i = SIZE - 1; i >= 0; i--) i--) 处理后 printf ("%d", a[i]); ("%d", printf (INT_STR, a[i]); (INT_STR, } }
a = 3.14; * 2 * 2;
错误! 错误!
第 十 章
预 处 理 命 令
{ N的内容是10 的内容是10 #define NUM2 20 { return (N * N); #define NUM (NUM1 + NUM2) int a = 2, b = 3; } void main ( ) a *= ( + 20) ; 10 { b = b * ( + 20) ; 10 //第二次宏定义 int a = #define N 20 //第二次宏定义 2, b = 3; printf ("a = %d, b = %d\n", a, b); %d\ void a *= NUM; main ( ) NUM; } { N的内容是20 的内容是20 b = b * NUM; NUM; printf ("%d%d\ N + f )); ("%d\n", \ printf ("a = %d, b = %d\n", a, (b); 预编译 输出结果: 输出结果: } 处理后 } a = 60, b = 50 90

C语言 第九章 预处理命令

C语言 第九章 预处理命令
第九章 预处理命令
目的: 简化程序的编写 ; 提高程序的模块化、可读性、可移植性。
有三种类型的预处理命令: 1. 宏定义命令; 2. 文件包含命令; 3. 条件编译命令。
为了与C语句区别,这些命令均以“ # ”开头。
处理流程: 第一次编译扫描时,将预编译命令处理完, 然后再进行正式编译,生成目标代码。
#define f(a)
(a)* b
若有:f(x+y) 则应有:
(x+y)b
若有:f(x+y+z) 则应有:
预编译后, z = f(x+y) 变成: z = x+y*b 结果为: z=31
(x+y+z)b
(这个结果与初始设想不一致)
“带参数宏定义” 必须注意以下几个方面: 1. 宏定义时要考虑实参(替换)的各种可能, 防止出 现二义性。
3. #include后的文件名既可用“ ”,也可用< >, 二者区别:
“ ”首先在当前目录中找,然后再去标准目录中找。
< > 只在标准目录(include目录)中找。
为提高预处理的搜索效率,通常对自定义的 非标准头文件使用方式一;而对系统提供的标准 头文件(如:math.h、stdio.h等)使用方式二。
将返回值 6 将返回值 8
但二者还是有区别的:
1) 宏替换在预编译时进行;
而函数调用在程序运行时进行
2) 宏展开时,仅仅是将宏体中的形参简单 地置换为实参,不计算实参值,也不会带来任何 返回值; 而函数调用要进行: l 计算实参值(假定用 2+3、 9–1作为实参将 被计算出来)、 l参数传递(将 5、8 传给形参x、y)、
这些文件要用到公用信息时,只要在文件 中加入#include “f.h”这么一行命令既可。这样 就不必在f1.c、…… 、fn.c每个文件中都去重 复定义这些公用的信息。

第九章 预处理命令

第九章 预处理命令
C语言程序设计 - 第6章 预处理
12
(3) 在调用函数时,对使用的实参有一 在调用函数时, 定的数据类型限制; 定的数据类型限制;而带参的宏的实 可以是任意数据类型。 参,可以是任意数据类型。 (4) 函数调用时,存在着从实参向形参 函数调用时, 传递数据的过程, 传递数据的过程,而带参数的宏不存在 这种过程。 这种过程。
说明
宏定义仅是把参数作为字符串做简单替换, 宏定义仅是把参数作为字符串做简单替换, 而不做任何运算求值和语法检查 宏名与参数表的括号之间不应有空格 应注意参数替换后可能出现的语法错误和意 料之外的运算 应在宏定义内容及其中参数两边加上括号
C语言程序设计 - 第6章 预处理 10
带参宏定义举例
#define S1(a,b) a*b #define S2(a,b) ((a)*(b)) #define max(a,b) ((a)>(b)?(a):(b)) ((a)>(b)?(a):(b)) int main() { int x=3, y=4, i=5, j=6, s, z; s=S1(x+y, x-y); /* s=x+y*x-y; s==11 */ xs=x+y*xs=S2(x+y, x-y); /* s=((x+y)*(x-y)); s==-7 */ xs=((x+y)*(xs==z=max(i++, j++); /* z=((i++)>(j++)?(i++):(j++)); */ z=((i++)>(j++)?(i++):(j++)); /* z==7, i==6, j==8 */ }

c语言程序设计第九章预处理命令

c语言程序设计第九章预处理命令
(1)一个include命令只能指定一个被包含文件,如果要包含 n个文件,要用n个include命令。
(2)如果文件1包含文件2,而文件2中要用到文件3的内容,则 可在文件1中用两个include命令分别包含文件 2和文件3, 而且文件3应出现在文件2之前,即在 filel.c中定义: #include “file3.h” #include “file2.h”
(4)宏定义不是C语句,不必在行末加分号。如果加了分号则 会连分号一起进行置换。如:
#define PI 3.1415926; area=PI* r* r;
经过宏展开后,该语句为 area= 3.1415926;* r* r ; 显然出现语法错误。
(5)#define命令出现在程序中函数的外面,宏名的有效范围 为定义命令之后到本源文件结束。通常, #define命令写 在文件开头,函数之前,作为文件一部分,在此文件范围 内有效。
运行情况如下: input radius:4 l=25.1328 s=50.2655 v=150.7966
2、说明:
(1)宏名一般习惯用大写字母表示,以便与变量名相区别。 (2)使用宏名代替一个字符串,可以减少程序中重复书写某
些字符串的工作量。
(3)宏定义是用宏名代替一个字符串,也就是作简单的置换, 不作正确性检查。
(6)可以用#undef命令终止宏定义的作用城。例如:
# define G 9.8
main()
{ ...
}
# undef G
进行宏定义时,可以引用已定义的宏名,可以层层 置换。
例2 分析下面程序的运行结果
#define R 3.0 #define PI 3.1415926 #define L 2*PI*R #define S PI*R*R main() {

第九章 预处理命令

第九章 预处理命令

思考题1:执行下面程序后, 的值为多少 的值为多少? 思考题 :执行下面程序后,a的值为多少? #define SP(x) x*x main() { int a,k=2; a=SP(k); printf("%d\n",a); } 宏展开后为: 宏展开后为:a=k*k;
思考题2:执行下面程序后, 的值为多少? 思考题 :执行下面程序后,area的值为多少? 的值为多少 #define PI 3.1415926 #define S(r) PI*r*r main() { float a,b,area; a=2.6;b=2.4; area=S(a+b); printf("%f\n",area); } 宏展开后为: 宏展开后为:area=3.1415926*a+b*a+b; 16.8081 而不是: 而不是:area=3.1415926*(a+b)*(a+b); 78.5398
说明: 说明:
1) 定义带参数的宏时,宏名和后面的括号之间不能有 定义带参数的宏时, 空格,否则连空格一起作为字符串的一部分。 空格,否则连空格一起作为字符串的一部分。 2) 带参数的宏定义与函数不同: 带参数的宏定义 函数不同 宏定义与 不同: (1) 带参数的宏不考虑参数的类型,如果实参是表达 带参数的宏不考虑参数的类型, 不考虑参数的类型 也不求表达式的值,只是简单的字符串替换。 式,也不求表达式的值,只是简单的字符串替换。 宏展开是在预处理时进行的,在展开时, 宏展开是在预处理时进行的,在展开时,不分配存 储单元,也不进行值的传递。 储单元,也不进行值的传递。 函数调用是在程序运行时执行的 调用是在程序运行时执行的, (2) 函数调用是在程序运行时执行的,需要考虑参数 的类型,如果实参是表达式,需先求表达式的值, 的类型,如果实参是表达式,需先求表达式的值, 再进行参数传递。 再进行参数传递。

c语言 ●第9章 预处理命令

c语言 ●第9章 预处理命令
16
三、说明 1.要包含几个文件,就用几个 .要包含几个文件,就用几个#include。 。 2.可嵌套包含。 .可嵌套包含。 file1.c file2.c
#include <file2.c> …… #include <file3.c> ……
file3.c
没有文件包含 ……
等价于: 等价于:file1.c
2
输入半径,求圆的周长、圆的面积、球体积。 例9.1 输入半径,求圆的周长、圆的面积、球体积。 #include <stdio.h> #define PI 3.14159 void main() { float r,l,s,v; printf("r=?"); scanf("%f",&r); l=2*PI*r; s=PI*r*r; v=4.0/3.0*PI*r*r*r; printf("l=%.4f,s=%.4f,v=%.4f\n例9.4 利用宏展开得到若干个结果
#include <stdio.h> #define PI 3.14159 #define CIRCLE(R,L,S,V) L=2*PI*R; S=PI*R*R; V=4.0/3*PI*R*R*R void main() { float r,l,s,v; printf("r=?"); scanf("%f",&r); CIRCLE(r,l,s,v); /* 设r=2.0 */ /* l=2*3.14159*2.0;s=3.14159*2.0*2.0; */ /* v=4.0/3*3.14159*2.0*2.0*2.0; */ printf("r=%.2f,l=%.2f,s=%.2f,v=%.2f\n",r,l,s,v); } 结果:r=3.50,l=21.49,s=38.48,v=179.59 结果:

第9章 预处理命令

第9章 预处理命令

#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); }


宏与函数没有任何关系! 宏只是简单的字符的替代! 宏的处理是在通常编译之前,更是在程 序运行之前,与内存、函数的实参、形 参、函数返回值没什么关系。 可以把宏代换看成是系统帮我们去完成 源程序的编辑。


“文件包含”处理 一个源文件可以将另外一个源文件的全 部内容包含进来。 可以理解为:系统将另外一个源文件的 内容帮我们抄写到当前文件中,以便当 前文件在编译时使用另外源文件中的内 容。
printf(“L=%f,S=%f”,2*3.14*3.0,3.14*3.0*3.0);

带参数的宏定义 一般形式: #define 宏名(参数表)字符串 带参数的宏在展开时,不是进行简单的 字符串替换,而是进行参数替换。
#define S(a,b) a*b area=S(2,3);
#define S(r) PI*r*r area=S(a+b);
预编译
area=PI*a+b*a+b;
本来想用a,b的和做为半径,可是• • • • • • 系统不会去帮你加括号


怎么解决???
在定义时加括号 #define S(r) PI*(r)*(r) area=S(a+b);

计算机程序设计c语言第09章预处理命令

计算机程序设计c语言第09章预处理命令

10
② 定义有参宏时,宏名与左圆括号之间不能留有空格。否 则,C编译系统将空格以后的所有字符均作为替代字符 串,而将该宏视为无参宏。
2014-11-16
一、宏定义
有参宏与有参函数比较
11
① 调用有参函数时,是先求出实参值,然后再代入形参。而展 开有参宏时,只是将实参简单地置换形参。 ② 调用有参函数,在程序运行时处理,为形参分配临时的 内存单元。而宏展开在编译前进行,不分配内存单元, 不进行值传递,不返回值。 ③ 函数无论调用多少次,都不会使目标程序变长,但每次 调用都要占用系统时间进行调用现场保护和现场恢复; 宏展开不占运行时间,但是每引用1次,都会使目标程序 增大1次。 2014-11-16
2014-11-16
三、条件编译
3. #if 表达式 程序段1; [#else 程序段2;] #endif
19
功能:当表达式为非0(“逻辑真”)时,编译程序 段1,否则编译程序段2。
2014-11-16
小结
20
宏定义 “文件包含”处理 条件编译
2014-11-16
作 业
作 业:9-2,9-3 上机:9-6

P207 例9.3
2014-11-16
一、宏定义
说明
① 有参宏的展开,只是将实参作为字符串,简单地置 换形参字符串,而不做任何语法检查。
若定义:#define S(r) PI*r*r 则语句:area=S(a+b) 替换后为area=PI*a+b*a+b 要得到area=PI*(a+b)*(a+b),需定义为: #define S(r) PI*(r)*(r)
21
思考题:
一般程序在什么情况下使用宏定义?

第九章 预处理命令

第九章 预处理命令

#define R 3.0 #define PI 3.1415926 #define L 2*PI*R #define S PI*R*R main() {printf(“S=%f\n”,S);} #undef L #undef S void fun() {…}
#include <stdio.h> #define IN scanf #define OUT printf #define N 2 void main() {int i; char name[N][20]; long num[N]; OUT("Please input name and ID:\n"); for (i=0;i<N;i++) {IN("%s",name[i]); IN("%ld",&num[i]);} for (i=0;i<N;i++) {OUT("%s\t",name[i]); OUT("%ld\n",num[i]);} }
功能:当标识符在该条件 编译结构之前没有被# define定义过时,程序段 1被编译;否则,编译程 序段2
举例
#define debug main() {…… #ifdef debug printf(“x=%d,y=%d,z=%d\n”,x,y,z); #endif }
举例
#define inttag 1 main( ) {int ch; scanf(“%d”,ch); #if inttag printf(“%d”,ch); #else printf(“%c”,ch); #endif }
第九章 预处理命令
例如
#define squ(n) n*n

C_chap09 预处理命令

C_chap09 预处理命令

第ห้องสมุดไป่ตู้章 预处理命令
宏定义
在C语言源程序中允许用一个标识符来表示一个字符串, 语言源程序中允许用一个标识符来表示一个字符串, 称为“ 被定义为“ 的标识符称为“宏名” 称为“宏”。被定义为“宏”的标识符称为“宏名”。在 编译预处理时,对程序中所有出现的“宏名” 编译预处理时,对程序中所有出现的“宏名”,都用宏定 义中的字符串去代换, 这称为“宏代换”或“宏展开”。 义中的字符串去代换, 这称为“宏代换” 宏展开” 字符串去代换 宏定义命令完成的 宏定义是由源程序中的宏定义命令完成的。 宏定义是由源程序中的宏定义命令完成的。 宏代换是 由预处理程序自动完成的。宏定义的一般形式: 预处理程序自动完成的。宏定义的一般形式: 自动完成的 的一般形式 #define 宏名 字符串 在C语言中,“宏”分为有参数和无参数两种 语言中, 分为有参数和无参数两种 有参数
第九章 预处理命令
带参数的宏定义
C语言允许宏带有参数。在宏定义中的参数称为形式参数, 语言允许宏带有参数。在宏定义中的参数称为形式参数, 形式参数 实际参数。 在宏调用中的参数称为实际参数 在宏调用中的参数称为实际参数。 对带参数的宏,在调用中,不仅要宏展开, 对带参数的宏,在调用中,不仅要宏展开,而且要用实参 去代换形参。带参宏定义的一般形式为 的一般形式为: 去代换形参。带参宏定义的一般形式为: 宏名(形参表) #define 宏名(形参表) 字符串 在字符串中含有各个形参。 在字符串中含有各个形参。 带参宏调用的一般形式为 的一般形式为: 宏名(实参表) 带参宏调用的一般形式为: 宏名(实参表); 例如: 例如: /*宏定义 宏定义*/ #define M(y) y*y+3*y /*宏定义*/ : /*宏调用 宏调用*/ k=M(5); /*宏调用*/ : 在宏调用时,用实参5去代替形参y 在宏调用时,用实参5去代替形参y, 经预处理宏展开后的语 句为: 句为: k=5*5+3*5;

C语言程序设计第九章_预处理命令

C语言程序设计第九章_预处理命令

#define CHANGE 0 void main() {static char ch[]="China"; int i; #if CHANGE for (i=0;i<=strlen(ch)-1;i++) if (ch[i]!='z'||ch[i]!='Z') ch[i]+=1; else if (ch[i]=='z') ch[i]='a'; else ch[i]='A'; puts(ch); #else puts(ch); #endif }
注意: 1. 在宏定义语名后没有";" 2. 在Turbo C程序中习惯上用大写字符作 为宏替换名, 而且常放在程序开头。 3. 宏替换名可以带有形式参数, 在程序 中用到时, 实际参数会代替这些形式参数。 例如: #define EXCHANGE(a,b) temp=a;a=b;b=temp; Void main() { int temp,a,b; scanf("%d,%d",&a,&b); EXCHANGE(a,b) printf("%d,%d\n",a,b); }
#define MAX 200 main() { #ifdef MAX printf("compiled for bigger\n"); #else printf("compiled for small\n"); #endif
}
#ifndef、#else、#endif指令 #ifndef、#else、#endif指令
#if、#else、#endif指令 #if、#else、#endif指令

C语言程序第9章预处理命令

C语言程序第9章预处理命令

2.#ifndef 宏名 程序段1 #else 程序段2 #endif
作用:若宏名没有被#define定义过,则 编译程序段1,否则编译程序段2。与第一 种形式完全相反。
3.#if 表达式 程序段1 #else 程序段2 #endif
作用:若表达式为真,则编译程序段1, 否则编译程序段2。此编译命令类似于 if …else ….语句。
例程8-4代码: #include”stdio.h” #define CHANGE 1 int main(void) { char str[80],ch; int i=0;; gets(str); while((ch=str[i])!=’\0’) { #ifdef CHANGE str[i]++; if(str[i]>255) str[i]=0; #else str[i]--; if(str[i]<0) str[i]=255; #endif i++; } puts(str); }
9.1 概述
从语法上讲,预处理命令不是C语句,所以每条 预处理后面没有“;”号。但是,恰当地使用预处理命 令,可以改进程序设计环境,简化程序开发过程, 提高程序的可读性和移植性。 ANSI C中主要定义了如下三类预处理命令: 1. 宏定义 2. 文件包含命令 3. 条件编译命令
[返回]
9.2 深入了解宏
第9章 预处理命令
本章将详细介绍ANSI C标准规定的常见预处理 命令以及它们的用法。 • • • • • • 学习目标 ◇了解预处理命令的特点 ◇掌握宏定义的一般方法 ◇掌握文件包含命令的用法 ◇了解条件编译的作用和实现方法 ◇了解其它相关的预处理命令
9.1 9.2 9.3 9.4
概述 深入了解宏 条件编译 其它预处理命令

C程序设计第09章-预处理命令

C程序设计第09章-预处理命令

2- “文件包含”处 理
1、形式:
#include <文件名 文件名> 文件名

#include "文件名 文件名" 文件名
2、功能:将指定文件的全部内容代替该预处理行 将指定文件的全部内容代替该预处理行 file1.c #include <file2.c> file2.c file1.c
A
B
B A
条件编译命令大致有3种: 1、#if 条件 条件1
3-条件编译
源程序段1 源程序段 #elif 条件 条件2 源程序段2 源程序段 #else 源程序段3 源程序段 #endif 其中, elif是else if的缩写。 #elif和#else可以没有,但#endif必须存在,它是#if 命令的结尾。 #elif命令可以有多个。 if后面不能有扩号。 当某个条件被满足时,这个条件下面的源程序段是有效的,否则无效。 每个条件必须是一个常量表达式,通常会用到宏名。 命令都独占一行。
#define PI 3.14 #define S(r) PI*r*r area=S(a); area=S(a+b); #define S(r) PI*(r)*(r) area=PI*a*a; area=PI*a+b*a+b; area=PI*(a+b)*(a+b);
定义带参数的宏时,将宏体的形式参数用括号括起来; #define SQUARE(n) (n)*(n) x=SQUARE(a+b); x=(a+b)*(a+b); y=1.0/SQUARE(a+b); #define SQUARE(n) ((n)*(n)) y=1.0/((a+b)*(a+b)); 定义带参数的宏时,宏体和形式参数最好都用括号括起来; y=1.0/(a+b)*(a+b);

第9章:预处理命令

第9章:预处理命令

#define PI 3.1415926 main() { float l, s, r, v ; printf (“input radius :”) ; scanf (“%f ”, &r ) ; l=2.0*PI* l=2.0*PI*r ; s=PI* s=PI*r*r ; v =3.0/4*PI*r*r*r ; =3.0/4*PI* printf (“l =%10.4 f \ns =%10.4f \n v =%10.4f \n”, l, s, v); }
(2)文件file1.c 文件file1.c # include “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) ; }
printf (“r =%6.2f , l=%6.2f , s=%6.2f, v=%6.2f \n”, r, l, s, v) ; } 可知从宏带回: v三个表达式 可知从宏带回:l , s , v三个表达式
利用宏定义可以实现程序的简化,如事先定义 利用宏定义可以实现程序的简化, 输出格式” 好“输出格式”。 事先定义输出格式( 例9.5 事先定义输出格式(略)
注意: 注意:
(1)在编译时并不是作为两个文件进行连接 而是作为一个编译单位, 的,而是作为一个编译单位,得到一个目标文 .obj)而不是得到两个目标文件。 件(.obj)而不是得到两个目标文件。 被包含的文件可以是:扩展名.h (2)被包含的文件可以是:扩展名.h 或.c 或无扩展名 (3)被包含的文件若被重新修改,则凡包含 被包含的文件若被重新修改, 此文件的所有文件都要全部重新编译。 此文件的所有文件都要全部重新编译。 一个include命令只能指定一个被包含文 (4)一个include命令只能指定一个被包含文 件

级c语言第九章预处理命令

级c语言第九章预处理命令
⑵ 宏定义是用宏名代替一个字符串,只做简单的替代,不做正确性检查。如 果字符串书写错误,预处理时也照样进行替换。
⑶ 用宏名来代替字符串,可以减少程序输入过程中重复输入的某些字符串。
⑷ 宏定义时如果在行末有分号,则替换时连分号一起进行替换。例如:
#define X 5; …… s=X*8; ……
则经过宏展开后,该语句为:s=5;*8。显然出现语法错误。因此在宏定义 时,行末不要加分号。
带参数的宏展开过程为:预编译时遇到带实参的宏名,则按命令行 中指定的字符串从左到右进行置换。
其展开原则是:遇形参则以实参代替,非形参字符原样保留,从而 形成展开后的内容。
2021/1/28
整理课件
10
➢带参数的宏定义,其的作用域及其定义、使用方法与不带参数的宏定义相同。
➢不同的是,带参数的宏定义除了用字符串置换宏名之外,还要进行参数的置换,
例如: #define PI 3.1415926
PI是宏名,它代表字符串3.1415926。
注意:不要认为PI是一个值为3.1415926的变量。
宏定义与变量定义不同,宏定义只是在编译预处理时做简单的字符 串替换,并不需要系统分配内存空间;而定义变量则会在编译时得到系 统分配的内存空间。
2021/1/28
整课件
4
例1:利用宏定义求圆的周长和面积。
左面程序在编译前将进行宏展开,宏展开以后变为:
#define PI 3.1415926 #define R 1.0 Void main( ) { float k, s; k=2.0*PI*R; s=PI*R*R; printf(“周长=%f, 面积=%f\n″, k, s); }
⑻ 对于程序中写在双引号中的字符串,即使与宏名相同,也不对其进行 置换。例如,如果程序中有以下语句:

C语言程序设计_09章 预处理命令

C语言程序设计_09章 预处理命令
printf(“L=%f\nS=%f\n”,2*3.1415926*3.0,3.1415926*3.0*3.0);
Friday, May 06, 2011 四川理工学院计算机科学系 《C语言程序设计》 语言程序设计》 第 6页 LanJiming@ copyright
9.1.2 带参数的宏定义 带参数的宏定义也是一种替换操作, 带参数的宏定义也是一种替换操作,但它要进行两次替 宏名字符串被简单替换和实参字符串简单替换形参)。 换(宏名字符串被简单替换和实参字符串简单替换形参)。 其定义的一般形式为: 其定义的一般形式为: #define 宏名 参数表 字符串 宏名(参数表 参数表) 字符串中包含有参数表中所指定的参数。例如: 字符串中包含有参数表中所指定的参数。例如: #define S(a,b) a*b area=S(2,3); 其中S(2,3)相当与 其中 相当与2*3 。 相当与 带参宏定义的置换过程: 带参宏定义的置换过程:① 在程序中如果有带实参的宏 (例如 例如S(3,2)),则按#define命令行中指定的字 符串从左到右 例如 ,则按# 命令行中指定的字 进行置换; 如果字符串中含有宏中的形参(如 进行置换;② 如果字符串中含有宏中的形参 如a,b),则将 , 相应的实参字符串(可以是常量、变量或表达式)代替形参; 相应的实参字符串(可以是常量、变量或表达式)代替形参; 如果字符串中的字符不是参数字符(如上例中 如上例中*), ③ 如果字符串中的字符不是参数字符 如上例中 ,则原样 保留。这样,便形成了置换的字符串。 保留。这样,便形成了置换的字符串。
LanJiming@ copyright Friday, May 06, 2011 四川理工学院计算机科学系 《C语言程序设计》 语言程序设计》 第 9页

C09--预处理命令

C09--预处理命令

C语言程序设计 令
东华理工大学
第九章 预处理命
9.1.2带参数宏定义
一般形式: #define 宏名(参数表) 宏体 例 #define S(a,b) a*b 不能加空格 ……….. area=S(3,2); 宏展开: area=3*2; 宏展开:形参用实参换,其它字符保留 宏体及各形参外一般应加括号()
C语言程序设计 令
东华理工大学
第九章 预处理命
定义位置:任意(一般在函数外面) 作用域:从定义命令到文件结束 #undef可终止宏名作用域 格式: #undef 宏名
例 #define YES 1 main() { …….. } #undef YES #define YES 0 max() {…….. } YES原作用域
#else 程序段2 #endif 作用:当指定的表达式为真时,则在程序编 译阶段只编译程序段1,否则编译程序段2
C语言程序设计 令
东华理工大学
第九章 预处理命
其它的宏命令
§#error §#elseif §#elif §#undef §#line §#pragma §#define
C语言程序设计 令
YES新作用域
C语言程序设计 令
东华理工大学
第九章 预处理命
宏展开:预编译时,用宏体替换宏 名---不作语法检查 如 if(x==YES) printf(“correct!\n”); 引号中的内容与宏名相同也不置换
else if (x==NO ) printf(“error!\n”); 例 #define PI 3.14159 展开后: if(x==1 ) printf(“correct! \n”); 宏定义可嵌套,不能递归 printf(“2* PI=%f\ n”, PI*2); else if WIDTH (x==0 ) printf(“error! \n”); 宏展开: printf(“2* PI=%f\ n”, 3.14159*2); 例 #define 80 例 #define MAX MAX+10 ()
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
答案: BCE


#include <stdio.h> int s(); int x,y; main() {int n; x=1;y=2; n=s(); printf("x=%d,y=%d,n=%d",x,y,n);}
int s() {int z; x=3;y=4; z=x+y; return(z);} 程序运行后输出:___ 答案: 3,4,7

例9、6 (1)文件format.h #define PR pirntf #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”
运行结果: 1 12 123 1234 CHINA
§9.3 条件编译
当希望部分内容满足一定条件才进行编译,否则 不编译或这编译另一组语句,这就是“条件编 译”。 形式:
(1)# ifdef 标识符 程序段 1 else 程序段 2 # endif
作用:当指定的标识符已被#define命令定义过,则 在程序编译阶段只编译程序段1,否则编译程序段2。 # else 可没有,既 # ifdef 标识符 程序段1 # endif (2) # ifndef 标识符 程序段1 # else 程序段2 # endif 这里#ifndef 和 #ifdef不同,与第一种形式相反。 作用:若标识符未被定义过则编译程序段1,否 则编译程序段2。
§9.2 文件包含处理
“文件包含”处理是指一个源文件将另一个源文 件的全部内容包含进来。 形式:#include <文件名> 标准形式 或 #include “文件名” 例如以前用过的: #include <math.h> 数学头函数 #include <stdio.h> 输入/输出头函数 作用:可以节省程序设计人员的重复劳动。
三、带参的宏定义与函数的区别 函数调用时,要求出实参表达式的值,而宏 定义是简单的字符替换。 对于函数中的形参、实参都要定义类型,而 宏不存在类型问题。 调用函数只能得到一个返回值,而用宏可以 设法得到几个结果。
虽然有参宏与有参函数确实有相似之处,但不同之处更多, 主要有以下几个方面:
/*引用无参宏求体积*/
printf("leng=%.2f,area=%.2f,volu=%.2f\n",l,a, v); }
例如: #define G 9.8 main( ) { …… } undef G f1( ) { …… }
在函数f1中G不起作用 宏定义C语句,不必在行末尾加分号。
所谓编译预处理是指,在对源程序进行编译之前, 先对源程序中的编译预处理命令进行处理;然后 再将处理的结果,和源程序一起进行编译,以得 到目标代码。
(3)、# if 表达式 程序段1 #else 程序段2 #endif
作用:当指定表达式值为真(非零)时就编译 程序段1,否则编译程序段2。 例9、7 输入一行字母字符,根据需要设置条 件编译,使之能将字母全改为大写输出,或全改 为小写输出。
程序如下: #define LETTER 1 main( ) {char str[20]= “C language”,c; int I; I=0; While((c=str[I])!=’\0’) {I++; 运行结果: #if LETTER C LANGUAGE if (c>’a’&& c<=z) 上题如果将第一行改 c=c-32; #else 为:#define LETTER 0 if (c>=’A’&& c<=’z’) 则在预处理时,对第二 c=c+32; 个IF语句处理,使大写变 #endif printf(“%c”,c); 为小写。 } cccc }
二、带参数的宏定义 形式:#define 宏名(参数表) 字符串 例如: #define S(a,b) a*b area=s(3,2); 以3、2分别代替宏定义中的形参a、b, 即用 3 *2 代替S(3,2)。 所以赋值语句展开为: area=3*2; 作用:不是简单的字符串替换,还要进行参 数替换。
说明
(1)编译预处理时,预处理程序将查找指定的被包 含文件,并将其复制到#include命令出现的位置上。 (2)常用在文件头部的被包含文件,称为“标题文件” 或“头部文件”,常以“.h”(head)作为后缀,简 称头文件。在头文件中,除可包含宏定义外,还可包 含外部变量定义、结构类型定义等。 (3)一条包含命令,只能指定一个被包含文件。如果 要包含n个文件,则要用n条包含命令。 (4)文件包含可以嵌套,即被包含文件中又包含另一 个文件。
1)调用有参函数时,是先求出实参的值,然后再复制一份给 形参。而展开有参宏时,只是将实参简单地置换形参。 2)在有参函数中,形参是有类型的,所以要求实参的类型与 其一致;而在有参宏中,形参是没有类型信息的,因此用于 置换的实参,什么类型都可以。有时,可利用有参宏的这一 特性,实现通用函数功能。 3)使用有参函数,无论调用多少次,都不会使目标程序变长, 但每次调用都要占用系统时间进行调用现场保护和现场恢复; 而使用有参宏,由于宏展开是在编译时进行的,所以不占运 行时间,但是每引用1次,都会使目标程序增大1次。
main()
{ float l,a,r,v; printf("Input a radius: "); /*PI是宏名,3.1415926用来替换宏名的常数*/
scanf("%f",&r);
l=2.0*PI*r ; a=PI*r*r ; /*引用无参宏求周长*/ /*引用无参宏求面积*/
v=PI*r*r*r*3/4;
§9.1 宏定义
9.1.1 不带参数的宏定义 1. 形式: #define 标识符 字符串 例如: #define PI 3.14159 作用:指定用标识符PI来代替“3.14159” 说明: 1)宏定义使用宏名代替一个字符串,不做 正确性检查。 2)可以用#undef命令终止宏定义的作用 域。
应用条件编译命令有什么好处呢?
如果不用条件编译处理,目标程序长,(因为对 所有语句都进行编译),运行时间长(因为在程序运 行时对if语句进行测试)。而采用条件编译,可以减 少被编译的语句,从而减少目标程序的长度,减少运 行时间。当条件编译段比较多时,目标程序长度可以 大大减少。
教师 课题负责人:陈香兰,1950年生,计算机专业,教 授,现任计算机软件教研室主任,兼任"全国高等院校计 算机基础教育研究会师范专业委员会"理事。研究方向: 计算机应用。发表论文30余篇;主编活主审高等院校通 用教材8本;完成省级以上课题8项;主讲过《数据结构 》、《C语言程序设计》等10余门主要技术基础课程及 专业核心课程;主持并指导教育实习、技能训练、课程 设计、毕业设计等各项教学实践;曾多次被评为院级优 秀教师及模范共产党员等光荣称号。
文件包含的优点:
一个大程序,通常分为多个模块,并由多个程 序员分别编程。有了文件包含处理功能,就可以将 多个模块共用的数据(如符号常量和数据结构)或
函数,集中到一个单独的文件中。这样,凡是要使
用其中数据或调用其中函数的程序员,只要使用文 件包含处理功能,将所需文件包含进来即可,不必 再重复定义它们,从而减少重复劳动。
例如 9.3 #define PI 3.1415926 #define S(r) PI*r*r main( ) {float a,area; a=3.6; area=S(a); /*area=3.1415926*a*a*/ printf(“r=%f\narea=%f\n”,a,area);} 运行结果: r=3.600000 area=40.715038

int func(int a,int b) {static int m=0,i=2; i+=m+1; m=i+a+b; return(m);}
C. 8,20 D. 8,8
A. 8,17 B. 8,16 答案: C
第九章 预处理命令
C 语言与其他高级语言的一个重要区别是可 以使用预处理命令和具有预处理的功能。 C提供的预处理功能有三种: 宏定义 文件包含 条件编译 分别用宏定义命令、文件包含命令、条件 编译命令来实现。 这些命令都以“#”号开头。

#include <stdio.h> int func(int a,int b); void main() {int k=4,m=1,p; p=func(k,m); printf("%d,",p); p=func(0,p); printf(“%d\n”,p)}

1.带参宏的调用和宏展开 (1)调用格式:宏名(实参表) (2)宏展开:用宏调用提供的实参字符串,直接置换宏定义命 令行中、相应形参字符串,非形参字符保持不变。 2.说明 (1)定义有参宏时,宏名与左圆括号之间不能留有空格。否则
C编译系统将空格以后的所有字符均作为替代字符串,而将
该宏视为无参宏。 (2)有参宏的展开,只是将实参作为字符串,简单地置换形参 字符串,而不做任何语法检查。在定义有参宏时,在所有 形参外和整个字符串外,均加一对圆括号。

file1.c #define “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); }
相关文档
最新文档