單元(Units)

單元(Unit)可將共用型別、函式、程序、常數、變數等宣告打包,供其他單元或主程式呼叫,等同於其他程式語言中的模組 / 套件

建立單元

單元分為兩大核心區塊:

interface 介面區:對外公開內容,其他檔案引入後可直接存取;

implementation 實作區:內部私有程式碼,僅當前單元可見,外部無法呼叫。

範例

建立名為 MyUnit.pas 的檔案,用於撰寫其中一個單元。

unit MyUnit;

{$ifdef FPC}
{$mode objfpc}{$H+}{$J-}
{$endif}

// 介面區:對外公開
interface

procedure MyProcedure(const A: Integer);
function MyFunction(const S: string): string;

// 實作區:私有程式邏輯
implementation

procedure MyProcedure(const A: Integer);
begin
  WriteLn('A + 10 is: ', A + 10);
end;

function MyFunction(const S: string): string;
begin
  Result := S + 'strings are automatically managed';
end;

end.Code language: JavaScript (javascript)

細心的讀者會發現,結尾的 end. 沒有對應的 begin?

Pascal 的單元(unit)語法結構與程式(program)不同

program 主程式:必須以 begin ... end. 做為程式執行入口

unit 單元:不需要全域 begin

整個單元結尾使用 end.(句號結尾代表檔案結束,無對應全域 begin)

  • interface 內撰寫函式/程序原型、型別、常數、全域變數;外部透過 uses 引入後即可呼叫;
  • implementation 僅撰寫完整函式實作,其中定義的區域程序、私有變數,外部單元無法存取;
  • 單元檔案以 unit 名稱; 開頭,end. 結尾。

主程式引入單元

我們的主程式檔案為 mydemo.pas

透過 uses 關鍵字載入自訂單元

{$ifdef FPC} {$mode objfpc}{$H+}{$J-} {$endif}
{$ifdef MSWINDOWS} {$apptype CONSOLE} {$endif}

program MyProgram;

// 引入自訂單元 MyUnit
uses
  MyUnit;

begin
  WriteLn(MyFunction('Note: '));
  MyProcedure(5);
  ReadLn;
end.Code language: PHP (php)

上方 uses 下方的 MyUnit; 指的是單元名稱,而非 pas 檔案名稱。

也就是 MyUnit.pas 內第一行程式碼 unit MyUnit; 所定義的名稱。

雖然檔名與單元名可不一致,但建議兩者同名;若名稱不同,uses 仍需填寫單元名而非檔名。

接下來編譯並執行,主程式會呼叫單元內的函式。

接下來編譯並執行

編譯完成後,專案目錄會多出兩個檔案

.ppu(Pascal Unit File,單元編譯資訊檔)

僅編譯單元檔(unit)時才會產生,主程式 program 不會生成 ppu 檔

  • 儲存單元 interface 介面區的編譯中繼資料:函式原型、型別、常數、匯出符號;
  • 後續其他檔案執行 uses MyUnit 時,編譯器不需重新解析 MyUnit.pas 完整原始碼,直接讀取 .ppu 快速驗證介面;
  • 大幅提升大型專案編譯速度,是 FPC 增量編譯的核心檔案。

MyUnit.o:MyUnit.pas 編譯後的二進位機器指令(完整實作區程式碼)

mydemo.o:mydemo.pas 主程式的機器碼

編譯器先將 pas 檔轉譯為獨立二進位 .o 目的檔,最後連結器合併所有 .o 檔,封裝成可執行檔 .exe

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *