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)的轉換例程,也沒包括用於格式化處理的特殊例程,如Format 和FormatFloat 例程。
表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語言還有一個非常重要的特徵:它允許程式設計者自定義資料型別,稱為“使用者自定義資料型別”,這在下一章進行討論。