Delphi 11 编程语言的完整介绍 作者:Marco Cantu 译者:豆豆爸
如前所述,程序结构的另一个特殊元素(除实际代码外)是编译指令。这些是编译器的特殊指令,格式如下:
{$X+}
有些编译指令只有一个字符,如上图所示,其中的加号或减号表示该指令是激活还是停用。大多数指令也有更长、更易读的版本,并使用 ON 和 OFF 来标记是否激活。有些指令只有较长的描述性格式。
编译指令不会直接生成编译代码,但编译指令会影响但编译器生成代码的方式。在许多情况下,使用编译指令可以代替更改集成开发环境项目选项中的编译器设置,但在有些情况下,你只想将特定的编译器设置应用于某个单元或代码片段。
我将介绍特定编译器指令,但在它们可能影响语言特性时再进行介绍。在本节中,我只想提及几个与程序代码流相关的指令:条件定义和包含。
条件定义指示编译器包含或忽略部分源代码。Delphi 中的条件定义有两种,一种是传统的 $IFDEF
和 $IFNDEF
,另一种是更新、更灵活的$IF
。
这些条件定义依赖于已定义的符号,或者对于 $IF
版本来说,可以依赖于常量值。定义的符号可以由系统预定义(例如编译器和平台符号),它们可以在特定项目选项中定义,或者可以通过另一个编译器指令 $DEFINE
在代码中引入。
传统的 $IFDEF
和 $IFNDEF
的格式如下:
{$IFDEF TEST}
// 如果 TEST 被定义,这部分将被编译
{$ENDIF}
{$IFNDEF TEST}
// 如果 TEST 未被定义,这部分将不被编译
{$ENDIF}
如果有多个条件,还可以使用 $ELSEIF
指令。
每个版本的 Delphi 编译器都有一个特定的定义,您可以使用它来检查是否针对产品的特定版本进行编译。如果您使用的是后来推出的功能,但又想确保代码仍能在旧版本下编译,则可能需要使用该定义。
如果您需要为某些较新版本的Delphi编写特定的代码,可以基于以下定义设置 $IFDEF
语句:
这些版本号的十进制数字表示编译器的实际版本(例如 Delphi XE5 中的 26)。该数字序列并非 Delphi 独有,而是可以追溯到 Borland 发布的第一个 Turbo Pascal 编译器(更多信息请参见附录 A)。
您还可以在 $IF
语句中使用内部版本常量,这样做的好处是可以使用比较运算符 (>=
) 而不是匹配一个特定的版本。版本常量称为 CompilerVersion
,在Delphi XE5中它被分配了浮点值26.0
,如下面的示例所示:
{$IF CompilerVersion >= 26)}
// 在Delphi XE5或更高版本中编译的代码
{$IFEND}
同样,你也可以为你要编译的不同平台使用系统定义,以防你需要某些代码是平台相关的(在 Object Pascal 中一般是个例外情况,不是常见的做法):
Windows MSWINDOWS
macOS MACOS
iOS IOS
Android ANDROID
Linux LINUX
下面是 HelloPlatform 项目的代码片段,其中包含基于上述平台定义的测试:
{$IFDEF IOS}
ShowMessage('Running on iOS上');
{$ENDIF}
{$IFDEF ANDROID}
ShowMessage('Running on Android');
{$ENDIF}
我想在这里介绍的另一个指令是 $INCLUDE 指令,在讨论 uses 语句时已经提到过。通过该指令,你可以在源代码文件的指定位置引用并包含源代码片段。有时,当代码片段定义了编译器指令和编译器直接使用的其他元素时,该指令可用于在不同单元中包含相同的代码片段。
使用单元时,单元只被编译一次。当你包含一个文件时,该文件的代码会在被添加的每个单元中编译(这就是为什么如果同一包含文件被嵌入到同一项目的不同单元中,通常应避免在包含文件中声明任何新标识符的原因)。那么,如何使用包含文件呢?一个好的例子就是你想在大部分单元中启用的编译器指令集,或者一些额外的特殊定义。
大型库经常使用包含文件来实现这一目的,FireDAC 库就是一个例子,它是一个数据库库,现已成为系统库的一部分。系统 RTL 单元展示的另一个例子是为每个平台使用单独的包含文件,并使用 $IFDEF 有条件地只包含其中一个平台。