计算机程序设计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语言程序设计 - 第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 结果:

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讲--预处理命令

说明: (1)宏名一般用大写字母表示以便与变量 分开,但不是规定而只是习惯。
(2)宏定义不是C语句,末尾不加分号。 (3)程序中双引号中的宏名不进行宏替换。
4

无参的宏定义使用举例
#define M 10 main( ) {int j,a[M]; for(j=0;j<M;j++) a[j]=j+1; for(j=0;j<M;j++) printf("%6d",a[j]); }
无参宏定义中的宏名M系统是作为符号 常量来处理的,因此可以用来定义数组。

5
二、带参数的宏定义
格式: 说明: (1) 参数表中的参数必须为变量,称为形参。 (2) 带参的宏定义展开是从左到右依次将实参字符串 代替形参字符串。 (3) 在宏定义时,宏名与带参的括号之间不应 留空格,而括号后面一定要留空格。 (4) 宏定义与函数不同,务必要进行宏替换后 再分析程序的运行结果。 #define 标识符(参数表) 字符串
带参的宏定义在分析程序之前先进行宏展开, S(a+b,c+d)展开时用a+b代替x,用c+d代替y, 展开的结果为:a+b*c+d
7

带参的宏定义使用举例
#define S(x,y) x*y main() { int a=3,b=4,c=5,d=6; a*b printf("a*b=%d\n", S ( a,b));) ; (a+b)*(c+d) printf("a+b*c+d=%d\n" , S((a+b),(c+d))); }
15

第9章 编译预处理命令

第9章  编译预处理命令
对带参数的宏定义在宏替换时,不仅要将程序中出现 的标识符用字符串代替,还要进行参数的替换。
9.1 宏定义
2.带参数的宏定义的一些说明
(1)对带参数的宏的展开只是将语句中的宏名后面括号内
的实参字符串代替#define命令行中的形参。 (2) 在宏定义时,在宏名与带参数的括号之间不应加空格,
否则将空格以后的字符都作为替代字符串的一部分。
9.2 文件包含
9.2.1 文件包含的一般形式 C语言提供了#include命令来实现“文件包含”的操作。 其一般形式为:
#include "文件名" 或 #include <文件名>
两种形式的区别:用双引号时,系统首先在当前文件所 在的文件目录中寻找被包含文件,如找不到,再到存放C库 函数头文件的目录中寻找。而用尖括号时,只在存放C库函 数头文件的目录中寻找被包含文件。
9.4 本章小结
本章主要讲述了宏定义、文件包含,以及条件编译等知识。 通过本章的学习,读者应掌握带参数和不带参数的 宏定义的一般格式及其相关说明;了解条件包含的一般 形式和相关说明;理解常用条件编译的形式,并能灵活 运用。
9.1 宏定义
9.1.2 带参数的宏定义
1.带参Байду номын сангаас的宏定义的格式 带参数的宏定义也称为函数宏,它的定义格式为:
# define 标识符(参数表) 字符串 字符串中要包含在括弧中指定的参数。如:
# define F(x) (x)*(x) # define MAX(x, y) (( x > y ) ? x : y)
9.3 条件编译
9.3.2 其他一些标准指令 (1)#error指令将使编译器显示一条错误信息,然后停 止编译。 (2)#line指令可以改变编译器用来指出警告和错误信息 的文件号和行号。 (3)#pragma指令没有正式的定义。编译器可以自定义 其用途。典型的用法是禁止或允许某些烦人的警告信息。

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命令只能指定一个被包含文 件

第9章 预处理命令

第9章 预处理命令

格式: #if 表达式 程序段 #endif 意义: 当表达式的值为“ 当表达式的值为“真”时,则对程序段进行编译,否则 跳过该段代码 格式: #ifndef 标识符 程序段1 程序段1 #else 程序段2 程序段2 #endif 意义: 当表达式的值为“ 当表达式的值为“真”时,则对程序段1进行编译,否 时,则对程序段1 则对程序段2 则对程序段2进行编译。
9.1.2 带参数的宏定义 格式: #define 标识符(参数表) 字符串 标识符(参数表) 意义: 告诉预处理程序对源程序中的标识符以后面的符号串替 代,并将字符串中出现的参数符号用参数代替。 例:#define 例:#define area(x) 3.1415926*x*x …… main() {printf(“%f\ {printf(“%f\n”,area(2.5));
使用带参数的宏定义应注意: 1. 宏定义的宏名(标识符)与左圆括号之间没有空格。 2. 整个宏扩展及各个参数一般要用括号括起。 3. 带参数的宏替换虽然在形式上与函数类似,但意义不同: a) 函数调用时,先计算表达式的值,然后代入形参,而 宏替换只是简单的字符串代入 b)函数调用是在运行时处理的,而宏替换是在编译时 b)函数调用是在运行时处理的,而宏替换是在编译时 (严格来说是在编译前)替换的。 c)函数要求参数的形参和实参类型一致,而宏替换没有涉 c)函数要求参数的形参和实参类型一致,而宏替换没有涉 及类型。 d)一般函数有返回值,而宏替换没有返回值。 d)一般函数有返回值,而宏替换没有返回值。
9.3 条件编译
条件编译是根据外部定义的情况去编译不同的源程序代 码,这样就使得同一源程序可以得到不同的代码,便于程序 的移植和调试。 格式: #ifdef 标识符 程序段 #endif 意义: 当标识符已被定义过,则对程序段进行编译,否则跳过该 段代码

级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页

第9章 预处理命令

第9章  预处理命令

的实参字符串代替#define命令行中的形参。
如上例程序改为: #define PI 3.1415926 #define S(r) PI*(r)*(r) #define S(r) PI*r*r main( ) { float a, b, area; a=3.6; b=4.1; area=S(a+b); printf(“r=%f\narea=%f\n”,a+b, area); }
f=21.08;
P(D, a, c ,e); P(F, b, d ,f); P(F, a+b, c+d, e+f); }
二、带参宏的定义
不是进行简单的字符串替换,还要进行参数替换. 格式: #define 宏名(参数表) 字符串
如: #define S(a , b) … area=S(3, 2); 再如: #define M(y) … k=M(5); a*b
则宏展开为: area=3.1415926*a+b*a+b
(2)宏定义时,在宏名与带参数的括号之间不应加 空格,否则将空格以后的字符都作为替代字符 串的一部分。 如:#define S (r) PI*r*r
(3)带参宏定义,形参不分配内存单元,因此不必 作类型定义(与函数区别之一)
§9.2 “文件包含”处理
#define LETTER 1 main() {char str[20]=“CLanguage”,c; int i; i=0; while((c=str[i]!=„\0‟) { i++; #if LETTER if(c>=„a‟&&c<=„z‟) c=c-32; #else if(c>=„A‟&&c<=„Z‟) c=c+32; #endif printf(“%c”,c); } }
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

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
思考题:
一般程序在什么情况下使用宏定义?
2014-11-16
一、宏定义
有参宏与有参函数比较
12
④ 在有参函数中,形参是有类型的,而且要求实参的类型与 其一致;而在有参宏中,形参没有类型信息,只是一个符 号代表,因此可以是任何类型。 ⑤ 函数调用只能得到一个返回值,而用宏可以设法得到几 个结果。
2014-11-16
二、文件包含
文件包含:一个源文件可以将另一个源文件的全部内容包含 进来。 格式: #include “包含文件名” 或 #include <包含文件名> ■ 两种格式的区别在于: ① 使用双引号:系统首先到当前目录下查找被包含文件,如果没 找到,再到系统指定的“包含文件目录”(由用户在配置环境 时设置)去查找。 ② 使用尖括号:直接到系统指定的“包含文件目录”去查找。一 般地说,使用双引号比较保险。
2014-11-16
一、宏定义
说明
① 宏名一般用大写字母表示,以便与变量区别。 ② 在宏展开时,预处理程序仅以按宏定义简单替换宏 名,而不作任何检查。如果有错误,只能由编译程 序在编译宏展开后的源程序时发现。
6
③ 宏定义不是C语句,所以不能在行尾加分号。否则, 宏展开时,会将分号作为字符串的1个字符,用于 替换宏名。 2014-11-16
14
2014-11-16
二、文件包含
说明:
15
① 一条包含命令,只能指定一个被包含文件。如果要包含n 个文件,则要用n条包含命令。 ② 编译预处理时,预处理程序将查找指定的被包含文件, 并将其复制到#include命令出现的位置上。
③ 文件包含可以嵌套,即被包含文件中又包含另一个文件。
2014-11-16
2014-11-16
一、宏定义
例:输入圆的半径,求圆的周长、面积和球的体积。要 求使用无参宏定义圆周率。
#include<stdio.h> #define PI 3.1415926
/*PI是宏名,3.1415926用来 替换宏名的 常数*/
5
void main() { float r,l,s,v; printf("Input a r: "); scanf("%f",&r); l=2*PI*r; /*引用无参宏求周长*/ s=PI*r*r; /*引用无参宏求面积*/ v=PI*r*r*r*3/4; /*引用无参宏求体积*/ printf("length=%.2f,area=%.2f,volume=%.2f\n", l, s, v); }
三、条件编译
条件编译:程序中一部分内容只在满足一定条 件时才进行编译,即对这一部分内容指定编译 的条件
16
作用:可有效地提高程序的可移植性,并广泛 地应用在商业软件中,为一个程序提供各种不 同的版本。
2014-11-16
三、条件编译
1. #ifdef 标识符 程序段1; [#else 程序段2;] #endif
① ② ③ C提供的预处理功能: 宏定义 文件包含 条件编译
3
2014-11-16
一、宏定义
1. 不带参数的宏定义 #define 标识符 字符串
4
① “define”为宏定义命令;
② “标识符”为所定义的宏名,通常用大写字母表 示,以便于与变量区别;
③ “字符串”可以是常数、表达式、格式串等。当 是一个常量时,则相应的“宏名”就是一个符号
件包含
文件包含的优点:
一个大程序,通常分为多个模块,并由多个程序 员分别编程。有了文件包含处理功能,就可以将多个 模块共用的数据(如符号常量和数据结构)或函数, 集中到一个单独的文件中。这样,凡是要使用其中数 据或调用其中函数的程序员,只要使用文件包含处理 功能,将所需文件包含进来即可,不必再重复定义它 们,从而减少重复劳动。
17
功能:当“标识符”已经被#define命令定义过,则 编译程序段1,否则编译程序段2。
2014-11-16
三、条件编译
2. #ifndef 标识符 程序段1; [#else 程序段2;] #endif
18
功能:与第一种形式的作用相反,若“标识符”未被 #define命令定义过,则编译程序段1,否则编译程序 段2。
第九章
预处理命令
主要任务: 1.掌握宏定义的用法; 2.了解文件包含的概念; 3.熟练掌握文件包含命令include的用法; 4.了解条件编译的概念
主要内容
2
宏定义 “文件包含”处理 条件编译
2014-11-16
预处理命令
编译预处理:在对源程序进行编译之前,先对源程序中 的编译预处理命令进行处理;然后再将处理的结果,和 源程序一起进行编译,以得到目标代码。
一、宏定义
说明
④ 宏定义命令#define出现在函数的外部,宏名的有 效范围是:从定义命令之后, 到本文件结束。通 常,宏定义命令放在文件开头处。 ⑤ 可以用#undef命令终止宏定义的作用域
7
⑥ 在进行宏定义时,可以引用已定义的宏名 。
2014-11-16
一、宏定义
说明
⑦ 对双引号括起来的字符串内的字符,即使与宏名同 名,也不进行宏展开。 ⑧ 宏定义只作字符替换,不分配内存空间
8
使用宏定义的优点
① 可提高源程序的可维护性 ② 可提高源程序的可移植性 ③ 减少源程序中重复书写字符串的工作量
2014-11-16
一、宏定义
2. 带参数的宏定义 #define 宏名(形式参数表) 字符串

9
调用格式:宏名(实参表) 宏展开:用宏调用提供的实参字符串,直接置换 宏定义命令行中相应形参字符串,非形参字符保 持不变。
相关文档
最新文档