DELPHI的编译指令{$IFDEF WIN32}

对于Delphi来说﹐左右大括号之间的内容是批注﹐然而「{$」(左括号后紧接着货币符号)对于Compiler(编译器)而言并不是批注﹐而是写给Compiler看的特别指示。应用时机与场合

Delphi中有许许多多的Compiler Directives(编译器指令)﹐这些编译指令对于我们的程序发展有何影响呢? 它们又能帮我们什么忙呢?Compiler Directive 对程序开发的影响与助益, 可以从以下几个方向来讨论:协助除错

版本分类

程序的重用与管理

设定统一的执行环境

协助除错

稳健熟练的程序设计师经常会在开发应用系统的过程中﹐特别加入一些除错程序或者回馈验算的程序﹐这些除错程序对于软件品质的提升有极其正面的功能。然而开发完成的正式版本中如果不需要这些额外的程序的话﹐要想在一堆程序中找出哪些是除错用的程序并加以删除或设定为批注﹐不仅累人﹐而且容易出错﹐况且日后维护时这些除错程序还用得着。

此时如果能够应用像是$IFDEF的Compiler Directives ﹐就可以轻易的指示Delphi要/不要将某一段程序编进执行文件中。

同时﹐Compiler本身也提供了一些错误检查的开关﹐可以预先对程序中可能的问题提醒程序设计师注意﹐同样有助于撰写正确的程序。版本分类

除了上述的除错版本/正式版本的分类之外﹐对于像是「试用版」「普及版」「专业版」的版本分类﹐也可以经由Compiler Directive的使用﹐为最后的产品设定不同的使用权限。其它诸如「中文版」「日文版」「国际标准版」等全球版本管理方面﹐同样也可以视需要指示Delphi特别连结哪些资源档或者是采用哪些适当的程序。以上的两则例子中﹐各版本间只需共享同一份程序代码即可。Delphi 1.0 与 Delphi 2.0有许多不同之处﹐组件资源文件(.DCR)即是其中一例﹐两者的档案格式并不兼容﹐在您读过本文之后﹐相信可以写出这样的程序﹐指示Delphi在不同的版本采用适当的资源文件以利于组件的安装。{$IFDEF WIN32}

{$R XXX32.DCR}

{$ELSE}

{$R XXXX16.DCR}

{$EDNIF}

程序的重用与管理

经过前文的讨论后﹐相信你已经不难看出Compiler Directives在程序管理上的应用价值。对于原始程序的重用与管理﹐也是Compiler Directives 使得上力的地方. 举例来说:Pascal-Style字符串是Delphi 1.0与 Delphi 2.0之间的明显差异﹐除了原先的短字符串之外﹐Delphi 2.0之后还多了更为方便使用的长字符串﹐同时﹐系统也额外提供了像是 Trim() 这样的字符串处理函式。假如您有一个字符串处理单元必须要同时应用于Delphi 1.0 与 2.0的项目时﹐编译指示器可以帮你的忙。此外﹐透过像是{$I xxxx} 这样的 Compiler Directives﹐我们也可以适当的含入某些程序, 同样有助于切割组合我们的程序或编译设定。设定一致的执行环境

项目小组的成员间﹐必须有共同的环境设定﹐我很难预料一个小组成员间彼此有不同的{$B}{$H}{$X}设定﹐最后子系统在并入主程序时会发生什么事。此外, 当您写好一个组件或单元需要交予第三者使用时, 使用编译指示器也可以保证组件使用者与您有相同的编译环境。使用Compiler Directives指令语法

Compiler Directives从外表看起来与批注颇为类似, 与批注不同的是:Compiler Directives的语法格式都是以「{$」开始, 不空格紧接一个名称(或一个字母)表明给Compiler的特别指示, 再加上其它的开关或参数内容, 最后以右大括号作为指令的结束, 例如:

{$B+}

{$R-}

{$R MyCursor.res}

同时, 就如同Pascal的变量名称与保留字一样, Compiler Directives也是不区分大小写的。

从指令的语法格式来说Compiler Directives﹐可以进一步分类成以下三种格式:开关指令(Switch directives)

这类指令都是单一字母以不空格的方式连接「+」或「-」符号; 或者是开关名称以一个空格后连接「ON」或「OFF」来表示作用/关闭某一个编译指示开关。例如:{$A+}

{$ALIGN ON}

开关型的编译指令不一定要分行写, 它们可以组合在同一个编译指示的批注符号之间, 但必须以逗号连接, 而且中间不可以有空格, 例如:

{$B+,H+,T-,J+}

光标停留在程序编辑器的任一位置时按下Ctrl+O O, 完整的Compiler Directives将会全部列于Unit的最上方。参数指令(Parameter directives)

有些Compiler Directives需要在编译名称后面连接自定的参数(文件名称或指定的内存大小), 例如: {$R MyCursor.res}, 即在指示Delphi在编译连结时, 含入「MyCursor.res」这个资源档。条件指令(Conditional directives)

指示Compiler在编译的过程中, 按我们设定的条件, 选择性的采用/排除不同区域的程序代码。以下是一个条件编译的例子, 第一与第三列是写给Compiler看的,指示 Compiler在 __DEBUG这个条件名称完成定义的情况才编译ShowMessage()这列程序;反之, 如果 __DEBUG 当时没有定义的话, 这段程序几乎与批注无异, Compiler对它将视而不见。

{$IFDEF __DEBUG}

ShowMessage(IntToStr(i));

{$ENDIF}

如何从IDE改变Compiler directives设定从Delphi的IDE程序整合发展环境, 我们很方便的就可以修改各个compiler directives的设定, 方法是: 从Delphi IDE主选单: Project/Options/Compiler, 直接核选/取消各个CheckBox。值得注意的是, 改变一个项目的Compiler directives并不会影响其它的项目, 换言之, 各个项目都保有自己一套编译指示。

假如您希望其它的项目也采用相同一套的Compiler directives, 在上述ProjectOptions对话盒的左下方有一个「Default」选项, 选取这个CheckBox之后, 虽然对于既有的项目没有作用, 但未来新的项目都将可以采用这组设定作为默认值。

将Compiler directives写入程序透过Delphi的整合环境设定Compiler directives的确十分简便, 但是许多情况下我们仍然需要将Compiler directive直接加到程序中。至少有两个原因支持我们这么作:局部控制编译条件

在Project/Options/Compiler中所作的设定, 影响所及是整个项目, 如果某一段程序要特别使用不同的编译设定, 就必须直接将编译指示加到程序中。下列这段取自Online Help的程序范例, 即应用了{$I}编译指令局部控制在发生I/O错误时不要举发例外讯息, 这样, 我们就可以编译出一支在这段程序区域中不会产生I/O例外讯息的档案侦测函数。function FileExists(FileName: string): Boolean;

var

F: file;

begin

{$I-}

AssignFile(F, FileName);

FileMode := 0; ( Set file access to read only }