cpp宏使用.doc_第1页
cpp宏使用.doc_第2页
cpp宏使用.doc_第3页
cpp宏使用.doc_第4页
cpp宏使用.doc_第5页
已阅读5页,还剩12页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1 无参宏定义无参宏的宏名后不带参数。其定义的一般形式为: #define 标识符 字符串其中的“#”表示这是一条预处理命令。凡是以“#”开头的均为预处理命令。“define”为宏定义命令。“标识符”为所定义的宏名。“字符串”可以是常数、表达式、格式串等。在前面介绍过的符号常量的定义就是一种无参宏定义。此外,常对程序中反复使用的表达式进行宏定义。例如: #define M (y*y+3*y)它的作用是指定标识符M来代替表达式(y*y+3*y)。在编写源程序时,所有的(y*y+3*y)都可由M代替,而对源程序作编译时,将先由预处理程序进行宏代换,即用(y*y+3*y)表达式去置换所有的宏名M,然后再进行编译。【例】#define M (y*y+3*y)main() int s,y; printf(input a number: ); scanf(%d,&y); s=3*M+4*M+5*M; printf(s=%dn,s); 上例程序中首先进行宏定义,定义M来替代表达式(y*y+3*y),在s=3*M+4*M+5* M中作了宏调用。在预处理时经宏展开后该语句变为:s=3*(y*y+3*y)+4*(y*y+3*y)+5*(y*y+3*y);但要注意的是,在宏定义中表达式(y*y+3*y)两边的括号不能少。否则会发生错误。如当作以下定义后: #difine M y*y+3*y在宏展开时将得到下述语句: s=3*y*y+3*y+4*y*y+3*y+5*y*y+3*y;这相当于: 3y2+3y+4y2+3y+5y2+3y;显然与原题意要求不符。计算结果当然是错误的。因此在作宏定义时必须十分注意。应保证在宏代换之后不发生错误。对于宏定义还要说明以下几点:1) 宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种简单的代换,字符串中可以含任何字符,可以是常数,也可以是表达式,预处理程序对它不作任何检查。如有错误,只能在编译已被宏展开后的源程序时发现。2) 宏定义不是说明或语句,在行末不必加分号,如加上分号则连分号也一起置换。3) 宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束。如要终止其作用域可使用# undef命令。例如: #define PI 3.14159 main() #undef PIf1() 表示PI只在main函数中有效,在f1中无效。4) 宏名在源程序中若用引号括起来,则预处理程序不对其作宏代换。【例】#define OK 100main() printf(OK); printf(n); 上例中定义宏名OK表示100,但在printf语句中OK被引号括起来,因此不作宏代换。程序的运行结果为:OK这表示把“OK”当字符串处理。5) 宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名。在宏展开时由预处理程序层层代换。例如: #define PI 3.1415926#define S PI*y*y /* PI是已定义的宏名*/对语句: printf(%f,S);在宏代换后变为: printf(%f,3.1415926*y*y);6) 习惯上宏名用大写字母表示,以便于与变量区别。但也允许用小写字母。7) 可用宏定义表示数据类型,使书写方便。例如: #define STU struct stu在程序中可用STU作变量说明: STU body5,*p; #define INTEGER int在程序中即可用INTEGER作整型变量说明: INTEGER a,b;应注意用宏定义表示数据类型和用typedef定义数据说明符的区别。宏定义只是简单的字符串代换,是在预处理完成的,而typedef是在编译时处理的,它不是作简单的代换,而是对类型说明符重新命名。被命名的标识符具有类型定义说明的功能。请看下面的例子: #define PIN1 int * typedef (int *) PIN2;从形式上看这两者相似, 但在实际使用中却不相同。 下面用PIN1,PIN2说明变量时就可以看出它们的区别:PIN1 a,b;在宏代换后变成: int *a,b;表示a是指向整型的指针变量,而b是整型变量。然而: PIN2 a,b;表示a,b都是指向整型的指针变量。因为PIN2是一个类型说明符。由这个例子可见,宏定义虽然也可表示数据类型, 但毕竟是作字符代换。在使用时要分外小心,以避出错。8) 对“输出格式”作宏定义,可以减少书写麻烦。【例】中就采用了这种方法。#define P printf#define D %dn#define F %fnmain() int a=5, c=8, e=11; float b=3.8, d=9.7, f=21.08; P(D F,a,b); P(D F,c,d); P(D F,e,f); 2 带参宏定义 C+语言允许宏带有参数。在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。 对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参。带参宏定义的一般形式为: #define 宏名(形参表) 字符串在字符串中含有各个形参。带参宏调用的一般形式为: 宏名(实参表); 例如: #define M(y) y*y+3*y /*宏定义*/ k=M(5); /*宏调用*/ 在宏调用时,用实参5去代替形参y,经预处理宏展开后的语句为: k=5*5+3*5【例】#define MAX(a,b) (ab)?a:bmain() int x,y,max; printf(input two numbers: ); scanf(%d%d,&x,&y); max=MAX(x,y); printf(max=%dn,max); 上例程序的第一行进行带参宏定义,用宏名MAX表示条件表达式(ab)?a:b,形参a,b均出现在条件表达式中。程序第七行max=MAX(x,y)为宏调用,实参x,y,将代换形参a,b。宏展开后该语句为: max=(xy)?x:y;用于计算x,y中的大数。对于带参的宏定义有以下问题需要说明:1. 带参宏定义中,宏名和形参表之间不能有空格出现。 例如把: #define MAX(a,b) (ab)?a:b写为: #define MAX (a,b) (ab)?a:b将被认为是无参宏定义,宏名MAX代表字符串 (a,b) (ab)?a:b。宏展开时,宏调用语句: max=MAX(x,y);将变为: max=(a,b)(ab)?a:b(x,y);这显然是错误的。2. 在带参宏定义中,形式参数不分配内存单元,因此不必作类型定义。而宏调用中的实参有具体的值。要用它们去代换形参,因此必须作类型说明。这是与函数中的情况不同的。在函数中,形参和实参是两个不同的量,各有自己的作用域,调用时要把实参值赋予形参,进行“值传递”。而在带参宏中,只是符号代换,不存在值传递的问题。3. 在宏定义中的形参是标识符,而宏调用中的实参可以是表达式。【例】#define SQ(y) (y)*(y)main() int a,sq; printf(input a number: ); scanf(%d,&a); sq=SQ(a+1); printf(sq=%dn,sq); 上例中第一行为宏定义,形参为y。程序第七行宏调用中实参为a+1,是一个表达式,在宏展开时,用a+1代换y,再用(y)*(y) 代换SQ,得到如下语句: sq=(a+1)*(a+1);这与函数的调用是不同的,函数调用时要把实参表达式的值求出来再赋予形参。而宏代换中对实参表达式不作计算直接地照原样代换。4. 在宏定义中,字符串内的形参通常要用括号括起来以避免出错。在上例中的宏定义中(y)*(y)表达式的y都用括号括起来,因此结果是正确的。如果去掉括号,把程序改为以下形式:【例】#define SQ(y) y*ymain() int a,sq; printf(input a number: ); scanf(%d,&a); sq=SQ(a+1); printf(sq=%dn,sq); 运行结果为:input a number:3sq=7 在这里总结宏的使用方法 欢迎补充1 条件include如下CODE#ifndef MAIN_H_ /如果没有定义MAIN_H宏,就执行下面的程序#define MAIN_H_ /定义MAIN_H宏,以后这段程序就不会再被include了,因为一开始就不满足ifndef条件其它内容#endif上面在看到头文件时会看到 作用就是阻止这个头文件被多次include多次include就会出现重复的定义情况 所以需要在每个头文件中都使用这个定义如果还不是很了解要怎样使用 可以看看 c的标准头文件 如fcntl.h2 条件编译如下CODE#ifdef _DEBUGprintf(this debug infon);#endif如果没有定义_DEBUG宏的话 那么上面那一行是不会编译进去的 但是定义了_DEBUG后 上面那行就会编译进去 可以写个简单的程序测试CODE#include int main()#ifdef _DEBUGprintf(hello worldn);#elseprintf(no debug);#endifreturn 0;第一次使用 gcc -D_DEBUG main.c第二次使用 gcc main.c运行两次的结果看3 定义为某个值 以便后面修改这个值时不用修改其它地方代码 只要修改这个宏的定义就可以了 如一个软件的多语言版本等 如下CODE#include #define PRINT_STR 你好 DDmain()printf(PRINT_STR);return 0;编译时 会把PRINT_STR代替成你好 DD以后想修改时就方便了另外也可以定义为函数#include #ifdef _DEBUG#define A(x) a(x)#else#define A(x) b(x)#endifint a(int x)return x+1;int b(int x)return x+100;int main()printf (A(10) value is %d,A(10);return 0;/code其实也可以定义成#define A a 但是 定义成A(x)后 只有A后面带一个(x)类型的 编译器才会执行替换 比较安全 可以保证只替换函数而不替换变量第四个可变参数宏有些时候定义一个宏来代替某个函数 但是这个函数是可变参数的话 那就需要考虑办法了定义方法如下CODE#define PRINT(.) printf(_VA_ARGS_)#include int main()PRINT(%d %s %s,1,吃饭了吗 smile MM:),n);return 0;第五个 宏组合 也就是# 和 #的用法# 是连接符号 连接两个宏#是把名字代替成字符串如下CODE#define s5(a) supper_ # a#include void supper_printf(const char* p )printf(this is supper printf:n%sn,a);int main() s5(printf)(hello owrld); return 0;#用法如下#include #define s(p) #pint main()printf(s(p)n);return 0;运行一下就知道了最后 附上网上找到的宏定义的概念 第一篇第九章 预处理命令预处理的概念:编译之前的处理C的预处理主要有三个方面的内容:宏定义、文件包含、条件编译预处理命令以符号“#”开头。9.1 宏定义9.1.1 不带参数的宏定义宏定义又称为宏代换、宏替换,简称“宏”格式:#define 标识符 字符串其中的标识符就是所谓的符号常量,也称为“宏名”预处理(预编译)工作也叫做宏展开:将宏名替换为字符串。掌握宏概念的关键是“换”。一切以换为前提、做任何事情之前先要换,准确理解之前就要“换”。即在对相关命令或语句的含义和功能作具体分析之前就要换,“不管三七二十一,先换了再说”。那么剩下的问题就简单了:1 把谁换掉?2 换成什么?#define PI 3.1415926把程序中出现的PI全部换成3.1415926li9_1.c说明:(1)宏名一般用大写(2)使用宏可提高程序的通用性和易读性,减少不一致性,减少输入错误和便于修改。例如:数组大小常用宏定义(3)预处理是在编译之前的处理,而编译工作的任务之一就是语法检查,预处理不做语法检查。(4)宏定义末尾不加分号;(5)宏定义写在函数的花括号外边,作用域为其后的程序,通常在文件的最开头。(6)可以用#undef命令终止宏定义的作用域(7)宏定义可以嵌套li9_2.c(8)字符串中永远不包含宏(9)宏定义不分配内存,变量定义分配内存。9.1.2 带参数的宏除了一般的字符串替换,还要做参数代换格式:#define 宏名(参数表) 字符串例如:#define S(a,B) a*barea=S(3,2);第一步被换为area=a*b;,第二步被换为area=3*2;类似于函数调用,有一个哑实结合的过程li9_3.c(1)实参如果是表达式容易出问题#define S® r*rarea=S(a+B);第一步换为area=r*r;,第二步被换为area=a+b*a+b;正确的宏定义是#define S® ®*®(2)宏名和参数的括号间不能有空格(3)宏替换只作替换,不做计算,不做表达式求解(4)函数调用在编译后程序运行时进行,并且分配内存。宏替换在编译前进行,不分配内存(5)宏的哑实结合不存在类型,也没有类型转换。(6)函数只有一个返回值,利用宏则可以设法得到多个值li9_4.c(7)宏展开使源程序变长,函数调用不会(8)宏展开不占运行时间,只占编译时间,函数调用占运行时间(分配内存、保留现场、值传递、返回值)li9_5.c分析该例中的9.2 “文件包含”处理一个文件包含另一个文件的内容格式:#include 文件名或#include 编译时以包含处理以后的文件为编译单位,被包含的文件是源文件的一部分。li9_6a.c li9_6b.c编译以后只得到一个目标文件.obj被包含的文件又被称为“标题文件”或“头部文件”、“头文件”,并且常用.h作扩展名。修改头文件后所有包含该文件的文件都要重新编译头文件的内容除了函数原型和宏定义外,还可以有结构体定义,全局变量定义(1)一个#include命令指定一个头文件(2)文件1包含文件2,文件2用到文件3,则文件3的包含命令#include应放在文件1的头部第一行。(3)包含可以嵌套(4)称为标准方式,系统到头文件目录查找文件文件名则先在当前目录查找,而后到头文件目录查找(5)被包含文件中的静态全局变量不用在包含文件中声明。9.3 条件编译有些语句行希望在条件满足时才编译。格式:(1)#ifdef 标识符程序段1#else程序段2#endif或#ifdef程序段1#endif当标识符已经定义时,程序段1才参加编译。格式:(2)#ifndef 标识符格式:(3)#if 表达式li9_7.c使用条件编译可以使目标程序变小,运行时间变短。预编译使问题或算法的解决方案增多,有助于我们选择合适的解决方案。1.简单的define定义#defineMAXTIME1000一个简单的MAXTIME就定义好了,它代表1000,如果在程序里面写if(i(y)?(x):(y);这个定义就将返回两个数中较大的那个,看到了吗?因为这个“函数”没有类型检查,就好像一个函数模板似的,当然,它绝对没有模板那么安全就是了。可以作为一个简单的模板来使用而已。但是这样做的话存在隐患,例子如下:#defineAdd(a,b)a+b;在一般使用的时候是没有问题的,但是如果遇到如:c*Add(a,b)*d的时候就会出现问题,代数式的本意是a+b然后去和c,d相乘,但是因为使用了define(它只是一个简单的替换),所以式子实际上变成了c*a+b*d另外举一个例子:#definepin(int*);pina,b;本意是a和b都是int型指针,但是实际上变成int*a,b;a是int型指针,而b是int型变量。这是应该使用typedef来代替define,这样a和b就都是int型指针了。所以我们在定义的时候,养成一个良好的习惯,建议所有的层次都要加括号。3.宏的单行定义#defineA(x)T_#x#defineB(x)#x#defineC(x)#x我们假设:x=1,则有:A(1)-T_1B(1)-1C(1)-1(这里参

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论