c 预处理 指令和c宏

上传人:小** 文档编号:89123292 上传时间:2019-05-18 格式:DOC 页数:9 大小:25KB
返回 下载 相关 举报
c 预处理 指令和c宏_第1页
第1页 / 共9页
c 预处理 指令和c宏_第2页
第2页 / 共9页
c 预处理 指令和c宏_第3页
第3页 / 共9页
c 预处理 指令和c宏_第4页
第4页 / 共9页
c 预处理 指令和c宏_第5页
第5页 / 共9页
点击查看更多>>
资源描述

《c 预处理 指令和c宏》由会员分享,可在线阅读,更多相关《c 预处理 指令和c宏(9页珍藏版)》请在金锄头文库上搜索。

1、C 预处理指令和C宏C预处理指令和C宏C语言程序在被编译成可执行文件时,也许你使用的IDE只需点击一下编译按钮,或者使用gcc编译器的,也是一条命令就完成了(当然使用命令时,会有些必须的参数)。但是真正实际情况,这个过程需要经历:预处理-编译-链接-装载。当然我们的编译器已经高度发达,将这些内容全部实现了。而预处理最长被我们使用一条指令是#include。我们用它来加载头文件。同时还会有些使用预处理指令的C宏或是编译条件等。一:首先先将C语言所有预处理指令简单介绍一下:1.#define指令:该条指令最常被用来定义符号常量或明显的常量,当然定一个类函数宏也是需要使用它的。每个#define行由

2、三部分组成,第一部分是指令自身#define,第二部分是所选择的缩略语,这些缩略语称为宏(macro)。第三部分为宏替换的主体(或列表)。举例如下:#definePXprintf(xis%dn,x)#definePXprintf(xis%dn,x)预处理指令宏主体(替换列表)其中对于第二部分(宏)有如下要求:宏的名字中不能有空格,而且必须遵循C变量命名规则:只能使用字母、数字和下划线(_)而且第一个字符不能为数字。同时要注意,对于所有预处理指令都是从开始到第一个换行符结束。#define指令的作用范围是从出现位置开始到文件结束。预处理器在处理时,将源文件中出现的宏用其主体做替换。而且这种替换是

3、可嵌套的。这种嵌套替换举例如下:#defineTWO2#defineFOURTWO*TWO则FOUR将被做如下处理:第一次替换后变为:TWO*TWO,再次替换后变为2*2。在const关键字得到C的支持后,又提供了一种创建常量的灵活方法。使用const可以创建全局常量和局部常量、数字常量、数组常量和结构常量。对使用#define定义的符号常量可以被用来指定标准数组的大小,与const的简单举例类比。#defineLIMIT20constintLIM=50;staticintdata1LIMIT;/合法staticintdata2LIM;/无效constintLIM2=2*LIMIT;/合法co

4、nstintLIM3=2*LIM;/无效在#define中使用参数。通过使用参数可以创建外形和作用都与函数相似的类函数宏。宏的参数也用圆括号括起来。举例如下:#defineMEANX,Y预处理指令宏(X和Y为宏的参数)替换主体带参数的宏外形与函数非常相似,但是在使用时与真正的函数调用不完全相同。如果不能理解替换这种预处理形式很有可能出现意料之外的错误。见如下例子程序:/*mac_arg.c-macroswitharguments*/#includestdio.h#defineSQUARE(X)X*X#definePR(X)printf(Theresultis%d.n,X)intmain(voi

5、d)intx=4;intz;printf(x=%dn,x);z=SQUARE(x);printf(EvaluatingSQUARE(x):);PR(z);z=SQUARE(2);printf(EvaluatingSQUARE(2):);PR(z);printf(EvaluatingSQUARE(x+2):);PR(SQUARE(x+2);printf(Evaluating100/SQUARE(2):);PR(100/SQUARE(2);printf(xis%d.n,x);printf(EvaluatingSQUARE(+x):);PR(SQUARE(+x);printf(Afterincrem

6、enting,xis%x.n,x);return0;使用gcc4.3.2编译后输出的结果如下:(在不同的编译器出现的结果可能不同)x=4EvaluatingSQUARE(x):Theresultis16.EvaluatingSQUARE(2):Theresultis4.EvaluatingSQUARE(x+2):Theresultis14.Evaluating100/SQUARE(2):Theresultis100.xis4.EvaluatingSQUARE(+x):Theresultis36.Afterincrementing,xis6.前两项的结果正确的但是接下来的则有些出乎意外。PR(S

7、QUARE(x+2);时x值为4,那么x+2的SQUARE(x+2)时应该是6*6结果应该为36。而程序运行的结果则是14.如果你使用替换原则将SQUARE(x+2)替换则变为x+2*x+2这时x=4则计算结果正是14.要处理这种情况(优先级问题),可以采用对替换主题加圆括号保证优先级。最好参数本身也使用括号,保证优先级正确性。修改如下:#defineSQUARE(X)X*X之后的情况类似。特别指出:EvaluatingSQUARE(+x):Theresultis36.将被替换成:+x*+x。这种运算顺序C语言没有给出规定,而这时对不同的编译器可能出现不同的结果,gcc4.3.2是在乘法运算前

8、进行了x自加操作。而编译器也可以产生5*6的情况。不一而别。这里就需要注意了,在宏中一般不要使用自增或自减运算符。2.#运算符:在宏中利用宏参数创建字符串。如果定义如下一个宏:#definePSQRXprintf(ThesquareofXis%dn,X*X这样使用宏:PSQR8);则输出为:ThesquareofXis64。该处双引号中的X并没有被替换,这是预处理的替换规则决定的。但是如果你希望在字符串中(双引号括起来的C语言认为是字符串)包含宏的参数。那么C语言提供了运算符来实现。例子程序如下:/*subst.c-substituteinstring*/#includestdio.h#def

9、inePSQR(x)printf(Thesquareof#xis%d.n,(x)*(x)intmain(void)inty=5;PSQR(y);PSQR(2+4);return0;输出如下:Thesquareofyis25.Thesquareof2+4is36.可以看出第一次,用y代替了X。第二次用2+4代替了X。3.#运算符:预处理器的粘合剂:和运算符一样,运算符可以用于宏的替换部分。另外还可以用于类对象宏的的替换部分。这个运算符吧两个语言符号组合成单个语言符号。例子程序如下:/glue.c-usethe#operator#includestdio.h#defineXNAME(n)x#n#d

10、efinePRINT_XN(n)printf(x#n=%dn,x#n);intmain(void)intXNAME(1)=14;/变成intx1=14;intXNAME(2)=20;/变成intx2=20;PRINT_XN(1);/变成printf(x1=%dn,x1);PRINT_XN(2);/变成printf(x2=%dn,x2);return0;输出如下:x1=14x2=20可以看到使用运算符后将x与n合并成一个字符串。可变参数宏:和_VA_ARGS_具体应用举例如下:#definePRprintf(_VA_ARGS_)假设之后用下面的方式调用该宏PRHowdy;PRwetigt=%d,

11、shipping=¥%fn,wt,sp;则第一次调用中_VA_ARGS_展开为一个参数。Howdy第二次调用中_VA_ARGS_展开为3个参数。wetigt=%d,shipping=¥%fn,wt,sp展开后代码为:printfHowdy;printfwetigt=%d,shipping=¥%fn,wt,sp;需要注意一点,省略号只能代替最后的宏参数。如下定义是错误的。#defineWRONGX,.,Y#X#_VA_ARGS_#Y4.#include:文件包含。预处理器发现该指令后,就会寻找后跟的文件名并把该文件的内容复制包含到当前文件中。详细内容可参见C语言的变量作用域及头文件中关于头文件部

12、分介绍。5.#undef取消定义:#undef指令取消已定义的一个给定#define。举例如下:例如;#defineLIMIT400#undefLIMIT/此处之后LIMIT是没有定义的。但是注意,C语言提供的几个预定义宏如:_DATE_和_FILE_等不可被取消。6.:#ifdef、#else和#endif及#ifndef:条件编译指令组合#ifdef、#else和#endif及#ifndef通过判断之后跟随的变量是否被#define定义而形成编译的条件。#ifdef判读后面的标识符是否为定义,而#ifndef则相反,判断是否未定义。#else则与两者中其一组合使用类似,if。else形式。

13、#endif用于指示结束位置。7.#if与#elif:条件编译指令组合。#if指令更像C语言中if;#if后跟常量整数表达式,如果表达式为非零值,则表达式为真。#elif则可以与#if组合形成if。elseif。elseif的条件组合序列。(早期预处理器可能不支持#elif)。举例如下:#ifSYS=1#includetest1.h#elifSYS=2#includetest2.h#elifSYS=3#includetest3.h#else#includetest.h#endif8.#line和#error#line指令用于重置_LINE_和_FILE_宏报告的行号和文件名。使用举例:#lin

14、e1000/把当前行重置为1000#line10cool.c/把行号重置为10,文件名重置为cool.c#error指令是预处理器发出一条错误消息,该消息饱和值了中的文本信息。可能的话编译过程应该中断。使用举例:#if_STDC_VERSION_!=199901L#errorNotC99#endif9.#pragma:编译器参数设定。这个指令在现代编译器中被扩展的比较强大,同时通过必要的指令集来完成编译指示。不做详细介绍。掌握以上预处理指令,和宏的实现。通过一些宏可以在编写程序时达到意想不到结果。二:宏的使用技巧举例:例一、用C宏,书写代码更简洁这段代码写网络程序的朋友都很眼熟,是Net/3中mbuf的实现。structmbufstructm_hdrmhdr;unionstructstructpkthdrMH_pkthdr;/*M_PKTHDRset*/unionstructm_extMH_ext;/*M_EXTset*/charMH_databufMHLEN;MH_dat;MH;charM_databufMLEN;/*!M_PKTHER,!M_EXT*/M_dat;上面的代码,假如我想访问最里层的MH_databuf,那么我必须写M_dat.MH.MH_dat.MH_databuf;这是不是很长,很难写呀?这样的代码阅读起来也不明了。其实,对于MH_pkthdr、MH_e

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 商业/管理/HR > 管理学资料

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号