⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 delphi_compile.txt

📁 很少见的DELPHI的编译指令说明文档
💻 TXT
📖 第 1 页 / 共 3 页
字号:
$R+ 
$WARNINGS ON 
    各指令的用法您可以参阅本章稍后对个别指令的说明, 全部打开这些开关吧! 这样不仅让您可以使用Delphi IDE的除错器, 对于程序编译与执行过程中的问题, Delphi也会适时的反应, 有助于写作正确的程序。

    此处有一个迷思有待澄清-「加入Dubug信息会不会让执行文件变大变慢啊?」, 不一定。 

    对于们像是$D+, $L+, $HINTS ON这些开关, 打开后, Delphi在编译时的确会额外加入一些除错信息, 使得.DCU的档案变大, 对于.EXE的档案大小并没有影响; 同时, 程序的执行速度也没有改变, 还可以应用IDE的除错器trace我们的程序, 值得应用。 

    对于像是$Q, $R等Compiler directive, 的确会影响执行文件的大小与速度, 然而这并不动摇我们在研发期间使用它们的决定, 请想想看, 值得为这一点点的速度放弃程序的正确性吗? 当然, 程序开发完成后, 正式出货的版本, 可以关闭这两个开关。 

    如果您写好了一个组件, 而且只预备提供.DCU, 由于没有.PAS可供Delphi IDE的Debugger追踪程序, 除错开关反而应该在组件脱手前关闭并重新编译.DCU, 否则会引起使用者那边找不到档案的例外讯息。 

善用{$I} 
    {$I FileName}是一个非常有用的Compiler directive.应用这个指令, 我们可以弹性的管理Compiler directive的设定。 

条件名称请加入前导符 
    不知道您有没有这个疑问 -- 如果用{$DEFINE}定义的条件名称与变量名称相同时会发生什么事? 

procedure TForm1.Button1Click(Sender: TObject); 
var 
TEST: integer; 
begin 
{$DEFINE TEST} 
{$IFDEF TEST} 
ShowMessage(''Test''); 
{$ENDIF} 
end; 

    以上的程序编译与执行都没有问题, 但条件名称与变量名称重复毕意容易让人混淆, 因此, 假如能适当的为编译条件名称之前加上诸如底线(_TEST), 程序会比较容易阅读。 

设定一致的编译环境 
    在您了解了Compiler Directives之后, 请立即开始着手修改您IDE中有关编译指示的各个开关并且设为Default, 这样, 日后您的项目乃至整个研发小组都将拥有共同一致的编译环境, 对于写出来的程序会以何种方式编译连结都了然于胸, 直接有助于子系统顺利并入主系统中。 

个别指令说明 
    有了之前对于Compiler directives的观念之后, 接下来的这一节我将一一介绍几个常用的Compiler Directive的用法与注意事项, 您可以从这一节中学到更多有关Compiler directives的知识与使用细节。 

{$A+} 字段对齐 
    在{$A+}(默认值)的情形下, 如果没有使用 packed 修饰词宣告的 record 型态,其字段会以CPU可以有效存取的方式向 1. 2. 4 等边界对齐, 以获取最佳的存取速度。以下列的程序示例来说: 

{$A+} 
type 
MyRecord = record 
ByteField: byte; 
IntegerField: integer; 
end; 
procedure TForm1.Button1Click(Sender: TObject); 
begin 
ShowMessage(IntToStr(SizeOf(MyRecord))); 
end; 

    ShowMessage在{$A+}时显示的结果是:「8」; 倘若是{$A-}, 那所得的结果是「5」, 按理说, Byte应该只要一个byte就足够了, 但是考虑到硬件的执行特性, 经过对齐后的record会有比较好的执行速度。 

    有关这个Compiler Directive要注意的事项是: 不管{$A}的开关是ON或OFF, 使用packed修饰过的记录宣告, 是一定不会对齐的. 例如: 

MyRecord = packed record // 不会对齐的记录宣告方式 

{$APPTYPE GDI} 应用程序型态 
    一般的情形下, Delphi会以{$APPTYPE GUI}的方式产生一个图形的使用者接口程序, 如果您需要产生一个文字屏幕模式的程序, 那可以经由: 

在.DPR中加入{$APPTYPE CONSOLE} 
从主选单: Project/Options/Linker/EXE and DLL Options, 核取「Generate Console Application」Check Box。 
    其它有关这个Compiler Directive的注意事项有: 

$APPTYPE不能应用在DLL的项目或单一的程序单元(Unit), 它只对.EXE有意义。而且只有写在.DPR中才有作用。 
我们可以应用System程序单元中的IsConsole函数在程序执行时侦测应用程序的类型。 
参阅Object Pascal手册第十三章可以知道更多有关Console Mode Application的信息。 
{$B-} 布尔评估 

请看以下的程序: 

if (Length(sCheckedDateString) <> 8) 
    or EmptyStr(sCheckedDateString) 
    or (sCheckedDateString = '' . . '') 
    or (sCheckedDateString = '' / / '') then 
begin 
Result := True; 
Exit; 
end; 
 

    假如sCheckedDateString的字符串内容是「85/12/241」(长度9)的话, 以上的if述句, 其实在第一个逻辑判断时就已经知道结果了, 即使不看后来的逻辑运算结果也知道整个式子会是真值。 

    假如您希望对整个逻辑表达式进行完整的评估 -- 尽管结果已知, 后来的逻辑运算也不影响整个的结果时仍要全部评估过, 请将这个Compiler directives设为{$B+}, 反之, 请设为{$B-}, 系统的默认值是{$B-}。 

{$D+} 除错信息 
    当程序以{$D+}(默认值)编译时, 我们可以用Delphi整合发展境境的Debugger设定 断点, 也可以使用Trace Into或Trace Info追踪程序的执行过程, 值得注意的 是, 以{$D+}编译的程序, 执行的速度并不会受到影响, 只不过编译过的DCU的档 案长度会加大, 但EXE档的大小不变。 

{$DEFINE条件名称} 定义条件名称 
    随着您对Compiler Directives的了解与应用程度的加深, 您会发现这是一个非常 实用的编译指示。 

    经常, 我们会因为除错需要﹑区别不同版本等缘故, 希望选择性的采用或排除某一段程序, 这个时候, 我们就可以先以$DEFINE定义好一个条件名称(Conditional name), 然后配合{$IFDEF条件名称}#{$ELSE}#{$ENDIF}指示编译器按指定的 条件名称之有无来选择需要编译的程序。

以下列的程序片断来说: 

{$DEFINE _ProVersion} 
procedure TForm1.Button1Click(Sender: TObject); 
begin 
{$IFDEF _Proversion} 
frmPrint.ShowModal; // A 
{$ELSE} 
ShowMessage(''很抱歉, 试用版不提供打印功能''); 
{$ENDIF} 
end; 

    编译器将会选择编译上述A的那列程序, 日后, 如果我们需要编译「简易版」的程序版本时, 只要: 

将{$DEFINE _ProVersion}那列整个删掉。 
或者, 将{$DEFINE _ProVersion}改成{-$DEFINE _ProVersion}, 让它变成普通 的批注 
或者, 在{$DEFINE _ProVersion}的下一列加上{$UNDEF _ProVersion}, 解除_ProVersion这个条件名称的定义。 
    这样, 由于_ProVersion这个条件名称未定义的缘故, Compiler就只会选择{$ELSE}下的那段程序, 重新编译一次, 不需费太多力气, 很容易的就可以制作出「简 易版」了, 省去了要同时维护两份程序的麻烦。 

使用$DEFINE时的其它注意事项如下: 

以{$DEFINE}定义的条件名称都是区域的。换句话说, 它的作用范围只在当时所 在的单元才有效, 即使定义在unit的interface, 由其它的unit以uses参考也没有 效, 仍然只有在目前的unit有作用。 
此外, 它的作用范围是从定义起, 到unit结尾或者以{$UNDEF}解除为止。 
如果程序单元中已经用{$DEFINE}定义了一个条件名称, 而且也没有用{$UNDEF}解除定义, 重新{$DEFINE}一个同样名称并没有作用, 换句话说, 它们是同一个. 
假如需要一个全域的条件名称, 您可以:主选单: Project / Options / Directories/Conditional 的 Conditionals 中填入条件名称。 
以下的标准条件名称, 是Delphi 2.0已经预先预备好的, 我们可以直接引用, 同时, 它们都是全域的, 任何Unit都可以参照得到。 
VER90: Delphi Object Pascal的版本编号。90表示9.0版, 日后若出现9.5版时 , 也会有VER95的定义。 
WIN32: 指出目前是在Win32(95, NT)作业环境 
CUP386: 采用386(含)以上的CPU时, 系统会提供本条件名称。 
CONSOLE: 此符号会于应用程序是在屏幕模式下编译时才定义。 
{$DESCRIPTION 描述内容} 

    应用{$DESCRIPTION}可以指定加入一段文字到.EXE或.DLL表头的模块描述进入点 (module description entry)中﹐通常我们会用这个Compiler Directive加入应 用程序的名称与版本编号到.EXE中。

例如: 

{$DESCRIPTION Dchat Version 1.0} 

{$X+} 扩充语法 

    这是为了与之前的Pascal版本前向兼容的编译指令, 虽然设定这个开关型的指令仍有作用, 但笔者建议您大可保留系统的默认值{$X+}, 在{$X+}下: 

不需要非得准备一个变量接受函数的传回值, 换句话说, 函数的传回值可以舍 弃, 此时, 就可以像是呼叫程序一样, 很方便的呼叫函数。 
支持Pchar型态与零基的字符数组作为C语言以Null结尾的字符串。 
{$HINTS OFF} 提示讯息 

打关{$HINTS}开关后, Compiler会提示程序设计师注意以下的情况: 

变量定义了却没有使用 
程序流程中不会执行的for或while循环 
只有存入没有取用的指定叙述。意思是说, 指定数据到某一个变量之后, 却没 有任何的程序参考取用这个变量值。 
{$HINTS ON} 
procedure MyTest; 
const _False = False; 
var 
I, J: integer; 
begin 
if _False then 
for I := 1 to 3 do ; 
J := 3; 
end; 
{$HINTS OFF} 

由于程序简单, 在两个$HINTS中间的程序, 我们不难看出: 

for循环不会执行到, I变量也因此不曾用过 

J := 3写了等于白写 

但在程序越写越长而日趋复雓时, 藉由{$HINTS ON}的协助, 比较容易察觉出程序 的毛病。 

{$IFDEF} {$IFNDEF} 

请参阅{$DEFINE}的说明, 在此补充说明{$IFNDEF}, 以下列程序来说, 即在指示 Compiler在_Test未定义时, 条件编译ShowMessage()那列程序: 

{$IFNDEF _TEST} 
ShowMessage(''_TEST not define''); 
{$ENDIF} 

换言之, {$IFNDEF}相当于{$IFDEF}的{$ELSE}部分。 

{$IFOPT 开关} 

    到底{$B}是开着或关着呢? 如果我们想要指示Compiler按照某一个编译开关当时的状态作我们指定的事, 应该该怎么做呢? 这时, {$IFOPT}就派得上用场了。例如: 

{$R+} 
{$Q-} // 特别指定为Q- 
{$IFOPT R+} // 如果 Range Check 是开启的话
ShowMessage(''程序是在 Range Check 开启状态下编译的''); // 这个 Q+ 也会在 IFOPT R+ 成立时才通知 Compiler 
{$Q+} 
{$ENDIF} 
{$IFOPT Q+} 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -