1. 程式人生 > >Delphi 之 第三課 詳解資料型別

Delphi 之 第三課 詳解資料型別

delphi中宣告資料型別用關鍵字Var,關鍵字Var可以在很多地方使用,如放在函式或過程的開始部分的叫區域性變數。放在單元中的叫全域性變數。delphi中資料型別分為三大類:即有序資料型別,實數型別和字元型別。在細分可以分成。整數型別,布林型別,字元型別,實數型別,日期和時間型別,自定義資料型別。等等。現在具體講解各種型別。

  其中有序資料型別,布林型別和字元型別按取值範圍劃分

大小 有符號 無符號
8 Bits

shortInt

-128 to 127

Byte

0 to 255

16 bits

SmallInt

-32768 to 32767

Word

0 to 65535

32 bits

LongInt

-2147483648 to 2147483647

LongWord

0 to 4294967295

64 bits  Int64  
16/32 bits Integer   Cardinal

  布林型別

布林值不同於布林型別,平時很少用到。ByteBool、 WordBool 和LongBool這三種布林型別的布林值比較特殊,只在Windows API 函式中才用到它們。我們常用的Boolean型別,真為True值為1,假為False值為0.

  字元型別

字元型別有兩種表示法:ANSIchar 和WideChar,第一種型別有8位字元,它屬於美國標準字元。第二種代表16位的字元,它是用Unicode字元,也就是雙位元組。

  常量字元

常量字元可以代表用一個符號來表示如‘K’,也可以用#78,後者也可以用chr(78)表示。用Ord函式可以相反的轉換Ord(k).

還有一些特殊的字元:

#9跳格(Tab鍵)

#10換行

#13回車(Enter鍵)

  有序型別

說明 作用
DEC 將引數值遞減1或一個特定的值
inc 將引數值增加1或一個特定的值
Odd 如果引數為奇數返回真
Pred 根據引數在其資料型別定義中的序列,返回引數的前驅值
Succ 返回引數值的後繼值
Ord 返回引數在其資料型別值集合中的序號
Low 返回引數對應有序資料型別的最小值
High 返回引數對應有序資料型別的最大值

  實數型別

     實數型別代表不同格式的浮點數。如single型別為4個位元組,Double型別為8個位元組,Extended浮點型別,佔10個位元組。

  Read型別在Delphi早期版本中佔6個位元組,基本現在不使用該型別。

  另外還有兩種奇怪的資料型別:Comp 型別和Currency 型別,Comp 型別用 8 個位元組描述非常大的整數(這種型別可支援帶有 18 位小數的數字);Currency 型別 (16 位版的Delphi不支援該型別) 表示一個有四位小數位的值,它的小數位長度是固定的,同Comp 型別一樣也佔 8 個位元組。正如名字所示,Currency 資料型別是為了操作很精確的四位小數貨幣數值才新增的。

  對實型資料,我們沒辦法編一個類似Range的程式,因為High 、Low及 Ord函式不能用於實型值。理論上說實型型別代表一個無限的數字集合;有序型別代表一個有限的數字集合。

注意:讓我進一步把上述問題解釋一下。對於整數 23,你能確定23 後面的數是什麼 ,因為整型數是有限的,它們有確定的值域範圍及排列順序。而浮點數即使在一個很小的值域範圍內也無限、無序。 事實上,在 23 和 24 之間有多少值? 哪個值是 23.46 後面的值? 23.47 還是 23.461,或者 23.4601? 這是很難說清的。

  

  因此,如問Char 型別字元 w 的順序位置是有意義的, 但同樣的問題對浮點型別數 7134.1562 就毫無意義。對於一個實型數,你能確切知道有沒有比它大的實型數,但是,如想探究給定的實數前到底有多少個實型數(這是Ord 函式的作用),是得不到結果的。

  實型型別在使用者介面程式設計中用得不多,但是Delphi從各方面支援實型型別,包括在資料庫方面的支援。由於支援IEEE浮點數運算標準,Object Pascal 語言完全適合於各類數值計算程式設計。如果對這部分感興趣,你可以參考Delphi 在System單元中提供的算術函式(詳細見Delphi 幫助)。

  日期時間型別

  Delphi 也用實型數表示日期和時間資料。但為了更準確起見,Delphi 特別定義了TDateTime 資料型別,這是一個浮點型別,因為這個型別必須足夠寬,使變數能容納年、月、日、時、分和秒、甚至毫秒。日期值按天計數,從1899-12-30開始,放在TDateTime 型別的整數部分;時間值則位於十進位制數的小數部分。

  TDateTime 不是編譯器可直接識別的預定義型別,它在System單元定義:

type
  TDateTime = type Double;

使用TDateTime 型別很簡單,因為Delphi 為該型別定義了一系列操作函式,表3.3列出了這些函式。

例程 作用
Now 返回當前日期及時間
Date 返回當前日期
Time 返回當前時間
DateTimeToStr 按預設格式將日期和時間值轉換為字串;特定格式轉換可用 FormatDateTime函式
DateTimeToString 按預設格式將日期和時間值拷貝到字串緩衝區
DateToStr 將TDateTime值的日期部分轉為字串
TimeToStr 將TDateTime值的時間部分轉為字串
FormatDateTime 按特定格式將日期和時間值轉換為字串
StrToDateTime 將帶有日期和時間資訊的字串轉換為TdateTime型別值,如串有誤將引發一個異常
StrToDate 將帶有日期資訊的字串轉換為TDateTime型別格式
StrToTime 將帶有時間資訊的字串轉換為TDateTime型別格式
DayOfWeek 根據傳遞的日期引數計算該日期是一星期中的第幾天
DecodeDate 根據日期值返回年、月、日值
DecodeTime 根據時間值返回時、分、秒、毫秒值
EncodeDate 組合年、月、日值為TDateTime型別值
EncodeTime 組合時、分、秒、毫秒值為TDateTime型別值

  為了顯示怎樣使用日期時間型別及其相關例程,我建了一個簡單的例子TimeNow。該例子在主窗體中設定了一個按鈕和一個列表框(ListBox)。開始執行時,程式自動計算並顯示當前的時間及日期,以後每次單擊按鈕 ,顯示從程式開始至當前的時間。

  下面列出了窗體的OnCreate 事件程式碼:

procedure TFormTimeNow.FormCreate(Sender: TObject);
begin
  StartTime := Now;
  ListBox1.Items.Add (TimeToStr (StartTime));
  ListBox1.Items.Add (DateToStr (StartTime));
  ListBox1.Items.Add ('Press button for elapsed time');
end;

  第一句中呼叫了Now 函式,這個函式返回當前的日期和時間,它的值儲存在StartTime 變數中,StartTime 變數是全程變數,其宣告如下:

var
  FormTimeNow: TFormTimeNow;
  StartTime: TDateTime;

我只添加了第二個宣告,第一個是由Delphi自動新增的。預設情況下的程式碼如下:

var
  Form1: TForm1;

  窗體名改變後,這個宣告被自動更新。使用全程變數實際上不是最好的辦法,更好的方法是使用窗體類的私有域,這涉及到面向物件的程式設計技術。

  接下來的三個語句向位於窗體左面的列表框新增三個條目,結果見圖3.3。列表框中的第一行顯示了TDateTime 值的時間部分字串、第二行顯示的是同一值的日期部分,最後一行顯示了一個簡單的提示。

圖 3.3:例TimeNow啟動時的輸出顯示

 

 

當用戶單擊Elapsed 按鈕時,上圖第三行字串被程式的計算結果代替:

procedure TFormTimeNow.ButtonElapsedClick(Sender: TObject);
var
  StopTime: TDateTime;
begin
  StopTime := Now;
  ListBox1.Items [2] :=  FormatDateTime ('hh:nn:ss',
    StopTime - StartTime);
end;

這串程式碼再次計算當前的時間,並顯示當前與程式開始之時的時間差,其中用到了其它事件中的計算值,為此不得不把該值存入全程變數。實際上,最好是採用基於類的變數。

注意:上面程式碼中所用ListBox的索引號為2,,而它代表的是第三行的顯示輸出,其原因是listbox的資料項是從零開始計數的:第一項計為0,第二項為1,第三項為2,依次類推,後面涉及陣列時再詳細討論這方面內容。

除了呼叫TimeToStr和 DateToStr 外,以上例子中還用到了功能強大的FormatDateTime 函式(關於格式化引數詳見Delphi 幫助檔案)。需要注意的是:當時間和日期轉換成字串時,其轉換格式取決於Windows 的系統設定。Delphi 從系統中讀這些值,並把它們拷貝到SysUtils 單元中宣告的幾個全程常量中,例如:

DateSeparator: Char;
ShortDateFormat: string;
LongDateFormat: string;
TimeSeparator: Char;
TimeAMString: string;
TimePMString: string;
ShortTimeFormat: string;
LongTimeFormat: string;
ShortMonthNames: array [1..12] of string;
LongMonthNames: array [1..12] of string;
ShortDayNames: array [1..7] of string;
LongDayNames: array [1..7] of string;

大部分全程常量與currency 和浮點數格式化有關,在 Delphi 幫助的 Currency and date/time formatting variables 主題下,你可找到完整的清單。

注意:Delphi 中有一個DateTimePicker 控制元件,它提供了選擇日期的常用途徑,即從一個日曆中選擇日期。

特定的Windows 型別

到目前為止,我們所看到的預定義資料型別都是Pascal 語言自身定義的型別。 Delphi 中還包含Windows系統定義的資料型別,這些資料型別不是Pascal語言的組成部分,而是Windows 庫的一部分。Windows 型別包括新增的預設型別(例如DWORD 或UINT)、各種記錄(或結構)型別及指標型別等。

Windows 定義的資料型別中,最重要的型別是控制代碼(handle),第九章中將討論這一型別。

型別對映及型別轉換

正如所知,你不能把一個變數賦給另一個不同型別的變數,如果你需要這麼做,有兩種方法供選擇。第一種方法是採用型別對映(Typecasting),它使用一個帶有目標資料型別名的函式符號:

var
  N: Integer;
  C: Char;
  B: Boolean;
begin
  N := Integer ('X');
  C := Char (N);
  B := Boolean (0);

你可以在位元組長度相同的資料型別之間進行型別對映。在有序型別之間或實型資料之間進行型別對映通常是安全的,指標型別及物件之間也可以進行型別對映 ,只要你明白自己在做什麼。

然而,一般來說型別對映是一種較危險的程式設計技術,因為它允許你訪問一個似是而非的值,該值好象是其它值的替身。由於資料型別的內部表示法之間通常互相不匹配,所以當遇到錯誤時會難以追蹤,為此你應儘量避免使用型別對映。

第二種方法是使用型別轉換例程。表3.4中總結了各種型別轉換例程。其中有些例程所涉及的資料型別將在下一節中討論。 注意表中沒有包括特殊型別(如TDateTime 和variant)的轉換例程,也沒包括用於格式化處理的特殊例程,如FormatFormatFloat 例程。

表3.4:型別轉換系統例程

例程 作用
Chr 將一個有序資料轉換為一個ANSI字元
Ord 將一個有序型別值轉換為它的序號
Round 轉換一個實型值為四捨五入後的整型值
Trunc 轉換一個實型值為小數截斷後的整型值
Int 返回浮點數的整數部分
IntToStr 將數值轉換為字串
IntToHex 將數值轉換為十六進位制數字符串
StrToInt 將字串轉換為一個整型數,如字串不是一個合法的整型將引發異常
StrToIntDef 將字串轉換為一個整數,如字串不合法返回一個預設值
Val 將字串轉換為一個數字(傳統Turbo Pascal例程用於向後相容)
Str 將數字轉換為格式化字串(傳統Turbo Pascal例程用於向後相容)
StrPas 將零終止字串轉換為Pascal型別字串,在32位Delphi中這種型別轉換是自動進行的
StrPCopy 拷貝一個Pascal型別字串到一個零終止字串, 在32位Delphi中這種型別轉換是自動進行的
StrPLCopy 拷貝Pascal型別字串的一部分到一個零終止字串
FloatToDecimal 將一個浮點數轉換為包含指數、數字及符號的十進位制浮點記錄型別
FloatToStr 將浮點值轉換為預設格式的字串
FloatToStrF 將浮點值轉換為特定格式的字串
FloatToText 使用特定格式,將一個浮點值拷貝到一個字串緩衝區
FloatToTextFmt 同上面例程,使用特定格式,將一個浮點值拷貝到一個字串緩衝區
StrToFloat 將一個Pascal字串轉換為浮點數
TextToFloat 將一個零終止字串轉換為浮點數

注意:在最近版本的Delphi Pascal 編譯器中,Round 函式是以 CPU 的 FPU (浮點部件) 處理器為基礎的。這種處理器採用了所謂的 "銀行家舍入法",即對中間值 (如 5.5、6.5) 實施Round函式時,處理器根據小數點前數字的奇、偶性來確定舍入與否,如 5.5 Round 結果為 6,而 6.5 Round 結果也為6, 因為 6 是偶數。

結束語

本章討論了Pascal的基本資料型別。Pascal語言還有一個非常重要的特徵:它允許程式設計者自定義資料型別,稱為“使用者自定義資料型別”,這在下一章進行討論。