第9章 宏定义1

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

例:使用带参数的宏
#include<stdio.h> #define PI 3.1415926 #define s(r) PI*r*r void main() { float a,area; a=3.6; area=s(a); printf(“r=%f\narea=%f\n”,a,area); }
条件编译实例2
#include <stdio.h> #define MAX 10 main() { #if MAX>99 printf("compile for array greater than 99"); #else printf("compile for small array"); #endif }
具体过程如下:
编译 目标程序 C源程序(有预处理命令) 连接 执行程序
C源程序(无预处理命令)
预处理编译
C语言提供了多种预处理功能,如宏定义、文 件包含、 条件编译等。合理地使用预处理功能 编写的程序便于阅读、修改、 移植和调试,也 有利于模块化程序设计。
预处理的命令有以下几个特点: 1.预处理命令均以#开头,结尾不加分号; 2.预处理命令可以放在程序中任何位置,作用 范围从定义处到文件结尾。
5.带参的宏和带参函数区别
(1)在函数调用时,是先求出实参表达式的值,再传递给形参, 而宏定义只是简单的字符替换;例如上面的S(a+b),在宏展开时并不 求a+b的值,而只将实参字符“a+b”代替形参r (2)函数调用是在程序运行时处理的,分配存储单元,而宏展开 (调用)是在编译预处理时进行的,展开时不分配内存单元,不进行 值传递,没有返回值的概念; (3)对函数实参和形参都要定义类型,而宏不存在类型,宏定义 时字符串可以是任何类型数据,一律看成字符串,宏名也没类型,只 是一个符号表示,展开时代入指定的符号即可。 如:#define CHAR1 CHINA(字符) #define a 3.6 (数值)
第9章
ຫໍສະໝຸດ Baidu
编译预处理
学习目标:
掌握宏定义、无参宏、有参宏、符号常量 掌握文件包含的意义 教学重、难点: 宏定义(重) 文件包含的使用(重) 条件编译(重、难点)
编译预处理是指,在对源程序进行编译之前, 系统将自动引用预处理程序对源程序中的预处理部 分作处理;然后再将处理的结果,和源程序一起进 行编译,以得到目标代码。
2. 关于不带参数的宏定义的几点说明:
(1)宏名一般用大写字母表示,便于与变量名区别;一般将字符个数较多的字 符串用一个宏名替换,减少程序中多处引用字符串书写错误。 (2)宏定义是用宏名来表示一个字符串,在宏展开时以该字符串取代宏名, 这只是一种简单的代换, 预处理程序对它不作任何检查。如有错误,只能在编 译已被宏展开后的源程序时发现。 (3)宏定义不是语句,在行末不加分号,如加上分号则连分号也一起置换。 (4)宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束。如
宏定义不是C语句,所以
不能在行尾加分号。否则,宏
展开时,会将分号作为宏体中 的1个字符。
在宏展开时,预处理程 序仅以宏体替换宏名,而不 作任何检查
【提问】以下这道题目的结果是多少?
例9.3 #define N 2 #define M N+1 #define NUM 2M+1 main( ) { int i; for (i=1; i<=NUM; i++) printf (“ %d \n”, i ); } 宏展开后的等价程序如下: main( ) { int i; for (i=1; i<=6; i++) printf(“ %d \n”, i ); }
文件包含:
1):所谓“文件包含”处理是指一个源文件可以将另外 一个源文件的全部内容包含进来,即将另外的文件包 含到本文件之中。C语言提供了#inClude命令用来实现 “文件包含”的操作。其一般形式为 2):一般表达形式: #include “文件名” 或 #include<文件名>
注意:
当使用文件包含在编译时并不是对两 个文件分别进行编译,然后链接得到目 标程序,而是在经过编译预处理后将头 文件包含到主文件中,得到一个新的源 程序,然后对这个文件进行编译,得到 一个目标程序。被包含的文件成为新的 源文件的一部分,而单独生成目标文件。
条件编译实例1
#include <stdio.h> #define TED 10 main( ) { #ifdef TED printf("Hi,Ted\n"); #else printf("Hi,Anyone\n"); #endif #ifndef RALPH printf("RAPLH not defined\n"); #endif }
#include<stdio.h> #define PI 3.1415926 void main() { float s,v,r,l; printf("请输入半径长度:"); scanf("%f",&r); l=2.0*PI*r; s=PI*r*r; v=4.0/3*PI*r*r*r; printf("l=%10.4f\ns=%10.4f\nv=%10.4f\n",l,s,v); }
5.带参的宏和带参函数区别
(4) 调用函数只可得到一个返回值,而用宏可以设法得到几个结果。 #define PI3.1415926 #define CIRCLE(r,l,s, v)L=2*PI*R;S=PI*R*R;v=4.0/3.0*PI*R*R*R main() {float r,l,s,v; scanf("%f",&r); CIRCLE(r,l,S,v); printf("r=%6.2f,l=%6.2f, S=%6.2f, v=%6.2f\n",r,l,S, 运行情况如下:3.5 v);} r= 3.50,l= 21.99, S= 38.48,v= 179.59
说明:
4): 文件包含可用双撇号,也可用尖括号。 它们的区别是: 尖括号:系统到存放c库函数头文件的目录中寻找要 包含的文件 双撇号:系统先在用户当前目录中寻找,找不到再 按尖括号的方式寻找。 5):被包含的文件与其所在的文件在预编译后已变成同一 文件
条件编译:
1):一般情况下,源程序中所有的行都参加编译。但是有时希望对其 中一部分内容只在满足一定条件才进行编译,也就是对一部分内容 指定编译的条件,这就是“条件编译”。 2):表达形式: #ifdef 标识符 程序段1 #else 程序段2 #endif #ifndef 标识符 程序段1 #else 程序段2 #endif #if 表达式 程序段1 #else 程序段2 #endif
说明:
1): 一个#include命令只能指定一个被包含文件,如果 要包含n个文件,要用n个#include命令。 2) :如果文件1包含文件2,而在文件2中要用到文件 3的内容,则可在文件1中用两个include命令分别包 含文件2和文件3,而且文件3应出现在文件2之前。 3): 在一个被包含文件中又可以包含另一个被包含文件, 即文件包含是可以嵌套的。
宏定义:
1:不带参数的宏定义 1) 用一个指定的标识符来代替一个字符串 2) 它的一般形式: #define 标识符 字符串 3) 作用:把标识符定义为字符串。在进行编译预处理时,• 译 编 系统就能够把程序中出现的标识符,一律用字符串去替换,然后 再对替换处理后的源程序进行编译。
例:使用不带参数的宏定义
7):宏定义只作字符替换,不分配内存空间 8) :对程序中用双撇号括起来的字符串原样输出
3、无参宏的应用举例
例 9.1 不带参数的宏的程序
#include <stdio. h> #define PI 3.115926 #define STRING This is a test main( ) { float r, s; printf (“ STRING \n"); scanf ("%f", &r); s=PI*r*r; printf (“ s=%10.3f\n",s); }
运行结果如下: r=3.600000 area=40.715038
带参宏定义说明:
(1) 对带参数的宏的展开只是将语句中的宏名后面括号内的实参字符 串代替#define命令行中的形参。但是,如果有以下语句: area=S(a+B);这时把实参a+B代替PI*r*r中的形参r,成为 area=PI*a+B*a+B;请注意在a+B外面没有括弧,显然这与程序设 计者的原意不符。原意希望得到area=PI*(a+B)*(a+B);为了得到 这个结果,应当在定义时,在字符串中的形式参数外面加一个 括弧。即#define S(r) PI*(r)*(r)在对S(a+B)进行宏展开时,将 a+B代替r,就成了PI*(a+B)*(a+B)这就达到了目的。 (2) 在宏定义时,在宏名与带参数的括弧之间不应加空格,否则将 空格以后的字符都作为替代字符串的一部分。例如,如果有 #define s (r)PI*r*r 被认为s是符号常量(不带参的宏名),它代表字符串“(r) PI*r*r”。 如果在语句中有area=S (a); 则被展开为area=(r) PI*r*r (a) 显然不对了。
注意:
实参r的值已知,可以从宏带回3个值(l,S, v)。其实,只不过是字符代替而已,将字符r 代替R,l代替L,S代替S,v代替V,而并未 在宏展开时求出l、S、v的值。
5.带参的宏和带参函数区别
(5) 使用宏次数多时,宏展开后源程序长,因为每展开一次都使程序 增长,而函数调用不使源程序变长。 (6) 宏替换不占运行时间,只占编译时间。而函数调用则占运行时间 (分配单元、保留现场、值传递、返回)。 一般用宏来代表简短的表达式比较合适。有些问题,用宏和 函数都可以。如: #define MAX(x,y) (x)>(y)?(x)∶(y) 赋值语句展开后为 main() t=(a+b)>(c+d)?(a+b)∶(c+d); {int a,b,c,d,t; t=MAX(a+b,c+d); } 注意:MAX不是函数,这里只有一个 main函数,中就能求出t的值。
例如:
#define G 9.8 void main() { … } #undef G f1() { …
}
_______ ↑ G的有效范围 -----↓----
2. 关于不带参数的宏定义的几点说明:
(5) 宏定义可以嵌套,但嵌套的宏定义名要是已经定义的宏名。在宏展 开时由预处理程序层层替换。例如: #define R 14.256 #define PI 3.1415926 #define S PI*R*R /* PI、R是已定义的宏名*/ 则语句 printf ("%f", s);在宏代换后变为 printf ("%f",3.1415926*14.256*14.256); (6)可用宏定义表示数据类型,使书写方便。 例如: #define STU int 在程序中可用STU替换数据类型int。
NUM宏展开: 2*N+1+1 再宏展开: 2*2+1+1
带参数的宏定义
1) :带参数的宏定义不是简单的字符替换,还要进 行参数替 换。 2) : 它的一般定义形式: #define 宏名(参数表) 字符串 字符串中包含在括弧中所指定的参数。如: #define s(a,b) a*b area=s(3,2); 定义矩形面积S,a和B是边长。在程序中用了s(3,2),把3、2分别 代替宏定义中的形式
例9.5、用宏代表输出格式
#define PR printf #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" main() {int a,B,C,D; char string[]="CHINA"; 1 a=1;B=2;C=3;D=4; 12 PR(D1,a); PR(D2,a,B); 123 PR(D3,a,B,C); 1234 PR(D4,a,B,C,D); CHINA PR(S,string); }
相关文档
最新文档