【问题标题】:How Delphi Compiles my codeDelphi 如何编译我的代码
【发布时间】:2010-12-04 14:21:52
【问题描述】:

Delphi 编译器将如何编译以下代码;

uses a_big_unit;


procedure TForm1.Button1Click(Sender: TObject);
var
acompont : T_a_big_component ;
begin

if (true = false ) then // or            if false then
begin
  bc :=  Tbig_component.create(self)

end;

在此代码中,true = false 永远不会发生,因此组件 acompont 永远不会创建。

delphi 在优化模式下编译时会省略这些未使用的单元和代码

以及何时使用单位

在 delphi 7 中,即使你只是使用 XPMan 单元; (不使用它拥有的任何组件(TXPManifest1)),仍然使用该单元并且每个组件都以主题显示;

有些人说如果不需要,Delphi 会省略单位;

那么Delphi如何识别一个单元是否对其调用的单元有影响

【问题讨论】:

  • 为什么不if false then
  • @Andreas Rejbrand If false 表示如果 false = true ;我的意思是 true = false LOL!
  • 检查一下怎么样?在 if 语句之前放一个断点(例如用asm int 3;end;),运行它,然后检查 if 语句是否丢失?
  • @Viveeshan 哈哈? false=truetrue=falsefalse 是等价的
  • @CodeInChaos 这就是为什么我把 LOL 放在上一条评论的末尾(LOL = 大笑)

标签: delphi optimization compiler-construction code-generation


【解决方案1】:

自己看看:编译代码并在调试器中运行。您将无法在 if false then 块内的任何语句上设置断点,并且您将无法在另一个单元的 Tbig_component 类的构造函数中设置任何断点。为什么?因为这些语句没有任何代码。

您还可以通过在 IDE 中打开反汇编视图来查看编译器生成的机器代码。它将显示每个源代码行的机器代码。您会发现不会为 if false then 块生成任何机器代码。

【讨论】:

  • 例外情况是,如果 bigunit 有一个引用 Tbig_component 的初始化块,那么无论如何都会包含它。在这种情况下,您需要在 uses 子句中 $ifdef away bigunit 以获得最小尺寸。
  • 在 delphi 7 中,即使你只使用 XPMan ;单元(不使用它拥有的任何组件),仍然使用单元并且每个组件都显示为主题; delphi 编译器如何聪明到可以忽略或不忽略
  • 正确 - 如果一个单元 A 是从一个项目使用的单元 B 中引用的,则单元 A 的初始化部分将链接到项目中。如果单元初始化代码涉及任何类类型,这些类也将被链接。但是,单独引用一个单元不应导致该单元内的类链接到项目中。某些东西必须引用类才能使其被链接。注册类、调用类函数或 IS 测试可能会导致类型被链接。
  • @Vibeeshan:XPMan 中的“XP”组件是一种将 XPMan 单元添加到 uses 子句的简单方法。该单元本身实际上包含一个 {$R} 编译器指令,用于包含实际清单。清单资源实际上不是“代码”,因此无法优化。
【解决方案2】:

阅读this paragraph。由于您的条件表达式将在编译时解析,优化器将丢弃then 下的所有语句。但是,不会排除整个单元。

【讨论】:

  • 根据单元中的代码(实际使用或通过祖先和元类对方法的可访问性),链接器可能会将其丢弃...
  • @Marjan Venema:不是真的。生成并查看地图文件。
  • @user205376:我猜这取决于你所说的“扔掉”。如果地图文件中提到的唯一行是 unit's end. 语句,那么不可否认,地图文件中提到了该单位,但在我看来,它实际上已被丢弃......跨度>
  • @Marjan Venema:是的,这是因为链接编辑器在每个符号的基础上工作,并且有问题的单元本身也是一个符号并且具有 reference count > 0(uses 子句) 即使它包含的任何东西都有 refcount = 0 并被淘汰(它不执行任何聚合决策)。
【解决方案3】:

我在 Delphi 2009 中使用 TTable 组件做了一些测试:

1)

unit Unit5;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, DB, DBTables, StdCtrls;

type
  TForm5 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  end;

var
  Form5: TForm5;

implementation

{$R *.dfm}

procedure TForm5.Button1Click(Sender: TObject);
var
  T: TTable;

begin
  if False then
    T:= TTable.Create(nil);
end;

end.

可执行文件大小 = 820736 字节。

现在我对上面的代码做了一点改动:

procedure TForm5.Button1Click(Sender: TObject);
var
  T: TTable;

begin
  if True then
    T:= TTable.Create(nil);
end;

可执行文件大小 = 844288 字节。

所以 Delphi 链接器足够聪明,可以消除大约 24K 的死 TTable 代码。

【讨论】:

    【解决方案4】:

    我无法检查这里,因为我已经多年不再使用 delphi,但我希望该单元能够被编译和包含,因为毕竟它们存在于代码中。但是没有代码可以调用它们(至少在那里)。 相反,条件 $IF 应该可以解决问题。

    【讨论】:

      【解决方案5】:

      Delphi 编译器足够聪明,可以删除不使用的代码。但是,即使您的代码没有直接引用该单元的内容,使用的单元仍然可以增加最终可执行文件的大小。

      如果单元有一个初始化-部分,那么该部分中引用的所有代码都将包括在内。

      如果该单元有链接资源(如 XPMan 单元),那么这些资源也将包含在您的 exe 文件中。

      要绝对确保在需要时排除某个单元,您需要使用如下条件指令:

      uses 
        {$ifdef usebigcomponent}
        BigUnit,
        {$endif} 
        SysUils;
      

      在上面的示例中,usebigcomponent 在项目选项的“条件定义”中定义或使用 {$define} 指令定义。当未定义 usebigcomponent 时,将排除该单位。条件指令将使您的代码更难阅读,因此您是否认为对于较小的可执行文件值得。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-10
        相关资源
        最近更新 更多