预处理指令详解_第1页
预处理指令详解_第2页
预处理指令详解_第3页
预处理指令详解_第4页
预处理指令详解_第5页
已阅读5页,还剩7页未读 继续免费阅读

下载本文档

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

文档简介

#pragma#pragma预处理指令详解在所有的预处理指令中,#Pragma指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的情况下,给出主机或操作系统专有的特征。依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。其格式一般为:#PragmaPara其中Para为参数,下面来看一些常用的参数。message参数。Message参数是我最喜欢的一个参数,它能够在编译信息输出窗口中输出相应的信息,这对于源代码信息的控制是非常重要的。其使用方法为:#Pragmamessage(“消息文本”)当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。当我们在程序中定义了许多宏来控制源代码版本的时候,我们自己有可能都会忘记有没有正确的设置这些宏,此时我们可以用这条指令在编译的时候就进行检查。假设我们希望判断自己有没有在源代码的什么地方定义了_X86这个宏可以用下面的方法#ifdef_X86#Pragmamessage(“_X86macroactivated!”)#endif当我们定义了_X86这个宏以后,应用程序在编译时就会在编译输出窗口里显示“_X86macroactivated!”。我们就不会因为不记得自己定义的一些特定的宏而抓耳挠腮了。另一个使用得比较多的pragma参数是code_seg。格式如:#pragmacode_seg(["section-name"[,"section-class"]])它能够设置程序中函数代码存放的代码段,当我们开发驱动程序的时候就会使用到它。#pragmaonce(比较常用)只要在头文件的最开始加入这条指令就能够保证头文件被编译一次,这条指令实际上在VC6中就已经有了,但是考虑到兼容性并没有太多的使用它。#pragmahdrstop表示预编译头文件到此为止,后面的头文件不进行预编译。BCB可以预编译头文件以加快链接的速度,但如果所有头文件都进行预编译又可能占太多磁盘空间,所以使用这个选项排除一些头文件。有时单元之间有依赖关系,比如单元A依赖单元B,所以单元B要先于单元A编译。你可以用#pragmastartup指定编译优先级,如果使用了#pragmapackage(smart_init),BCB就会根据优先级的大小先后编译。#pragmaresource"*.dfm"表示把*.dfm文件中的资源加入工程。*.dfm中包括窗体外观的定义。

#pragmawarning(disable:450734;once:4385;error:164)等价于:#pragmawarning(disable:450734)//不显示4507和34号警告信息#pragmawarning(once:4385)//4385号警告信息仅报告一次#pragmawarning(error:164)//把164号警告信息作为一个错误。同时这个pragmawarning也支持如下格式:#pragmawarning(push[,n])#pragmawarning(pop)这里n代表一个警告等级(1---4)。#pragmawarning(push)保存所有警告信息的现有的警告状态。#pragmawarning(push,n)保存所有警告信息的现有的警告状态,并且把全局警告等级设定为n。#pragmawarning(pop)向栈中弹出最后一个警告信息,在入栈和出栈之间所作的一切改动取消。例如:#pragmawarning(push)#pragmawarning(disable:4705#pragmawarning(disable:4706#pragmawarning(disable:4707)))//#pragmawarning(pop)在这段代码的最后,重新保存所有的警告信息(在这段代码的最后,重新保存所有的警告信息(包括4705,4706和4707)。pragmacomment(...)该指令将一个注释记录放入一个对象文件或可执行文件中。常用的lib关键字,可以帮我们连入一个库文件。每个编译程序可以用#pragma指令激活或终止该编译程序支持的一些编译功能。例如,对循环优化功能:#pragmaloop_opt(on)//激活#pragmaloop_opt(off)//终止有时,程序中会有些函数会使编译器发出你熟知而想忽略的警告,如“Parameterxxxisneverusedinfunctionxxx”,可以这样:#pragmawarn—100//Turnoffthewarningmessageforwarning#100intinsert_record(REC*r){/*functionbody*/}#pragmawarn+100//Turnthewarningmessageforwarning#100backon函数会产生一条有唯一特征码100的警告信息,如此可暂时终止该警告。每个编译器对#pragma的实现不同,在一个编译器中有效在别的编译器中几乎无效。可从编译器的文档中查看。C#预处理器指令控制流语句中的条件表达式是在运行时求值的。而C#预处理器指令是在编译时调用的。预处理器指令(preprocessordirective)告诉C#编译器要编译哪些代码,并指出如何处理特定的错误和警告。C#预处理器指令还可以告诉C#编辑器有关代码组织的信息。语言对比:C++ 预处理C和C++风格的语言包含一个预处理器(preprocessor),它是独立于编译器的一个实用程序,用于对代码进行整理,根据特殊的记号来采取特殊的行动。预处理器指令通常告诉编译器如何编译一个文件中的代码,而并不参与实际的编译过程。与此相反,C#编译器会将预处理器指令作为对源代码执行的常规词法分析的一部分。其结果就是,C#不支持更高级的预处理器宏,它最多只允许定义常量。事实上,''预编译器〃在C++中显得很贴切,但在C#中就属于用词不当。每个预处理器指令都以一个#开头,而且必须在一行中写完。换行符(而不是分号)标志着预处理器指令的结束。表3-4总结了所有预处理器指令。表3-4预处理器指令语句或表达式常规语法结构示例#if指令#ifpreprocessor-expression#ifCSHARP2codeConsole.Clear();#endif#endif#define扌旨令#defineconditional-symbol#defineCSHARP2#undef扌旨令#undefconditional-symbol#undefCSHARP2#error扌旨令#errorpreproc-message#errorBuggyimplementation#warning扌旨令#warningpreproc-message#warningNeedscodereview#pragma扌旨令#pragmawarning#pragmawarningdisable1030#line指令#lineorg-linenew-line#line467"TicTacToe.cs"#linedefault#linedefault#region扌旨令#regionpre-proc-message#regionMethodscode#endregio3・9・1排除和包含代码或许最常用的预处理器指令就是用于控制什么时候以及如何包含代码的指令。举个例子来说,要使代码能够同时由C#2.0和之前的C#1.2版本编译器进行编译,可以使用一个预处理器指令,在遇到1.2编译器的时候,就排除C#2.0特有的代码。我们的tic-tac-toe例子和代码清单3-52对此进行了演示。代码清单3-52遇到C#1.x编译器的时候排除C#2.0代码#ifCSHARP2System.Console.Clear();#endif在这个例子中,调用了System.Console.Clear()方法,这是只有2.0CLI才支持的方法。使用#if和#«门dif预处理器指令,这一行代码就只有在定义了预处理器符号CSHARP2的前提下才会编译。预处理器指令的另一个应用是适应不同平台之间的差异,比如用WINDOWS和LINUX#if指令将Windows和Linux特有的API包围起来。开发者经常用这些指令来取代多行注释(/*...*/),因为它们更容易通过定义恰当的符号或者通过一次搜索/替换来移除。预处理器指令最后一个常见的用途是调试。如果用一个#ifDEBUG指令将调试代码包围起来,那么在大多数IDE中,都能在最终的发布版本中移除这些代码。IDE默认将DEBUG符号用于调试编译,将RELEASE符号用于发布版本。为了处理else-if条件,可以在#if指令中使用#elif指令,而不是创建两个完全独立的#if块,如代码清单3-53所示。#endif3・9・2定义预处理器符号可以采取两种方式来定义预处理器符号。第一种方式是使用#define指令,如代码清单3-54所示。代码清单3-54一个#define例子#defineCSHARP2第二种方式是在为.NET编译的时候使用define选项,如输出3-27所示。输出3-27>csc.exe/define:CSHARP2TicTacToe.cs输出3-28展示了在使用Mono编译器的前提下,如何实现相同的功能。输出3-28>mcs.exe-define:CSHARP2TicTacToe.cs要添加多个定义,只需以分号分隔定义。使用编译器选项的优点在于,不需要更改源代码,所以可以使用相同的源代码文件来生成两套不同的二进制程序。要取消符号的定义,可以采取和使用#define相同的方式来使用#undef指令。3・9・3生成错误和警告有的时候,或许想要标记出代码中潜在的问题。为此,可以插入#error和#warning指令来分别生成一条错误或警告消息。代码清单3-55使用tic-tac-toe例子来发出警告:代码无法防止玩家多次输入同一步棋。输出3-29展示了结果。代码清单3-55用#warning来定义一个警告#warning""Samemoveallowedmultipletimes."输出3-29Performingmaincompilation......"tictactoe.cs(471,16):warningCS1030:#warning:'"Samemoveallowedmultipletimes."'Buildcomplete--0errors,1warnings包含#warning指令后,编译器会主动报告一条警告,如输出3-29所示。利用这种警告,可以标记出代码中可能存在的增强或者bug。它是提醒开发者任务尚未完结的好帮手。3・9・4关闭警告消息警告可以指出代码中可能存在的问题,所以非常有用。然而,有的警告可以忽略,所以有必要明确地关闭它们。C#2.0提供了预处理器指令#pragma来做到这一点,如代码清单3-56所示。代码清单3-56使用预处理器指令#pragma来禁用一个警告#pragmawarningdisable1030注意,在编译器实际输出的时候,会在警告编号之前附加CS前缀。然而,在用#pragma禁用一个警告的时候,不需要添加这个前缀。要重新启用警告,仍然可以使用#pragma指令,只是要在warning之后添加一个restore选项,如代码清单3-57所示。代码清单3-57使用预处理器指令#pragma来还原一个警告#pragmawarningrestore 1030上述两条指令正好可以将一个特定的代码块包围起来一一前提是我们已知该警告不适用于这个代码块。我们最喜欢禁用的一个警告或许就是CS1591。如果使用doc编译器选项来生成XML文档,但是没有对程序中的所有public项进行文档化,就会显示该警告。3・9・5nowarn:Vwarnlist>选项除F#pragma指令,C#编译器通常还支持nowarn:vwarnlist〉选项。它可以获得与#pragma相同的结果,只是不是把它加进源代码,而是把它作为一个编译器选项使用。除此之外,nowarn选项会影响整个编译过程,而#pragma指令只影响该指令所在的那个文件。例如在输出3-30中,我们在命令行上关闭了CS1591警告。输出3-30>esc/doc:generate.xml/nowarn:1591/out:generate.exeProgram.es利用#line指令可以改变C#编译器在报告错误或警告时显示的行号。主要是能够自动生成C#代码的实用程序和设计器使用这个指令。在代码清单3-58中,真实行号显示在最左侧。代码清单3-58#line预处理器指令#line113"TicTacToe.es"#warning"Samemoveallowedmultipletimes."#linedefault在上例中,使用#line指令后,编译器会将实际发生在125行的警告报告成在113行上发生,如输出3-31所示。输出3-31Performingmaincompilation......"tictactoe.cs(113,18):warningCS1030:#warning:'"Samemoveallowedmultipletimes."'Buildcomplete--0errors,1warnings在#line指令后添加一个default,会反转之前的所有#line的效果,并指示编译器报告真实的行号,而不是之前使用#line指定的行号。3.9.7可视编辑器提示C#提供了只有在可视代码编辑器中才有用的两个预处理器指令,也就是#region和#endregion。像MicrosoftVisualStudio.NETIDE这样的可视代码编辑器能够搜索源代码,找到这些指令,并相应地进行处理。C#允许使用#region指令声明一个代码区域。#region和#endregion必须成对使用,两个指令都可以选择在指令后面跟随一个描述性的字符串。除此之外,还可以将一个区域嵌套到另一个区域中。代码清单3-59展示了来自tic-tac-toe程序的例子。代码清单3-59#region和#endregion预处理器指令#regionDisplayTic—tac—toeBoard#ifCSHARP2System.Console.Clear();#endif//Displaythecurrentboard;border=0; //setthefirstborder(border[0]="|")//Displaythetoplineofdashes.//(〃〃n——+——+——"n")System.Console.Write(borders[2]);foreach(charcellincells){//Writeoutacellvalueandtheborderthatcomesafterit.System.Console.Write("{0}{1}〃,cell,borders[border]);//Incrementtothenextborder;border++;//Resetborderto0ifitis3.if(border==3){border=0;#endregionDisplayTic—tac—toeBoardVisualStudio.NET会检查上述代码,并提供一个树形控件来展开和折叠由#region和#endregion指令界定的一个代码区域(在代码编辑器窗口的左侧),如图3-5所示。预处理器指令2008—12—2216:54C#有许多名为预处理器指令的命令。这些命令从来不会被翻译为可执行代码中的命令,但会影响编译过程的各个方面。例如,预处理器可禁止编译器编译代码的某一部分。如果计划发布两个版本的代码,比如基本版本和企业版本,或者针对不同的.NETFramework版本进行编码,就可以使用这些指令。在Anthem.NET的代码中我们经常可以看到这种用法。预处理器指令的开头都有符号#。C#中并没有一个像C++那样的独立预处理器,所谓的预处理器指令仍由编译器处理。下面将对这些指令逐一介绍。#define和#undef#define可以定义符号。当将符号用作传递给#1彳指令的表达式时,此表达式的计算结果true。如#defineDEBUG它告诉编译器存在给定名称的符号,在本例中是DEBUG。这个符号不是实际代码的一部分,只在编译代码时存在。#undef正好相反,它删除一个符号。必须把#define和#undef命令放在C#源码的开头,即在要编译的任何代码之前。它不像C++中那样可以定义常数值。#define本身并无大用,它需要配合#if指令使用。如#defineDEBUGintDoSw(doublex){#ifDEBUGCOnsole.WriteLine("xis"+X);#edif}#if,#elif,#else和#endif这些指令告诉编译器是否要编译某个代码块。看下面的方法:staticvoidPrintVersion(){#ifV3Console.WriteLine("Version3.0");#elifV2Console.WriteLine("Version2.0");#elseConsole.WriteLine("Version1.0");#endif}上面的代码会根据定义的符号来打印不同的版本信息。这种方式成为条件编译。使用#if不是条件编译代码的唯一方式,C#还提供了通过Conditional属性的机制。#if和#elif还支持一组逻辑运算符!=,二二,!二和||。如果符号存在,符号的值被认为是true,否则为false,如:#ifV3||(V2==true)//if定义了V3或V2符号...#warning和#error这也是两个很有用的预处理器指令,编译器遇到它们时,会分别产生警告或错误信息。如果遇到#warning指令,会向用户显示#warning指令后面的文本。实际上,在VS2005中,IDE会直接将信息标识出来:^n'arrir普 汀日rnirrinfc而如果编译器遇到#error,就会立即退出编译,不会产生IL代码。使用这两个指令可以检查#define是不示做错了什么事,使用#warning可以让自己想起做什么事。#ifDEBUG&&RELEASE#e

温馨提示

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

评论

0/150

提交评论