变体类的使用 package record case【转载】
**************理論區?start*********************
DELPHI中記錄的存儲方式
?
?
?
在DELPHI中,我們用record關鍵字來表明一個記錄,有時候,我們還會看到用packed?record來聲明的記錄,這二者的區別就在于存儲方式的不同;在windows中,內存的分配一次是4個字節的,而Packed按字節進行內存的申請和分配,這樣速度要慢一些,因為需要額外的時間來進行指針的定位。因此如果不用Packed的話,Delphi將按一次4個字節的方式申請內存,因此如果一個變量沒有4個字節寬的話也要占4個字節!這樣浪費了一些空間,但提高了效率。
?
例如一個記錄,以,sizeof(okwary)應該得到8。而如果使用packed關鍵字,那么sizeof(okwary)則得到5。
?
???type?okwary=?record
?????age?:?integer;
?????sex?:?shortint;????
???end;
?
??????其中age是integer類型,正好4個字節,而sex是showint類型,占用一個字節,但基于4字節得內存分配方式,這里它也將占用4個字節。
?
?
DELPHI中的變體記錄
?
在DELPHI中,觀察Tmessage和TTypeData的定義,從關鍵字record,你一眼就可以看出,它是一個記錄類型,但仔細觀察,你又會發現在它的定義中出現了case關鍵字。它代表什么呢?
?
它代表此記錄是變體記錄。讓我們先去了解一下變體記錄。
?
一個典型的變體記錄定義如下:
?
type??recordTypeName??=??record??
???fieldList1:??type1;??
???...??
???fieldListn:??typen;??
case??tag:??ordinalType??of??
???constantList1:??(variant1);??
???...??
???constantListn:??(variantn);??
end;?
?
其中case到結尾部分定義了多個變體字段。所有變體字段共享一段內存大小又最大變體字段決定。
?
使用變體記錄時要注意:?
?
(1)Long??String、WideString、Dynamic??Array、Interface的大小都是指針大小,??OleVariant其實就是COM??SDK中的VARIANT結構,大小是16字節。
?
但在Object??Pascal中它們都需要自動終結化,如果它們出現在variant??part中,編譯器就無法知道它們是否應該進行終結化――因為不知道當前存儲的是哪種類型。???
?
(2)所有變體字段共享一段內存。而共享內存的大小則由最大變體字段決定。?
?
(3)當tag存在時,它也是記錄的一個字段。也可以沒有tag。?
?
(4)記錄的變體部分的條件域必須是有序類型
?
(5)記錄類型中可以含有變體部分,有點象case語句,但沒有最后的end,變體部分必需在記錄中其他字段的聲明之后
?
?
?
事實上Delphi中內存的幾乎所有的變體記錄都有一個特點(盡管這不是要求的),就是所有變體部份長度部和都是一樣的,比如:
?
???TMessage?=?packed?record
?????Msg:?Cardinal;
?????case?Integer?of
???????0:?(
?????????WParam:?Longint;
?????????LParam:?Longint;
?????????Result:?Longint);
???????1:?(
?????????WParamLo:?Word;
?????????WParamHi:?Word;
?????????LParamLo:?Word;
?????????LParamHi:?Word;
?????????ResultLo:?Word;
?????????ResultHi:?Word);
???end;
?
WParam,LParam,Result三個字段的長度和是12個字節,而WParamLo,WParamHi,LParamLo,LParamHi,ResultLo,ResultHi六個字段之和也是12個字符,同時仔細觀察,會發現后面六個字段中的每兩個字段與前面三個字段中的每一個字段都是對應的.
?
再看看
???TRect?=?packed?record
?????case?Integer?of
???????0:?(Left,?Top,?Right,?Bottom:?Longint);
???????1:?(TopLeft,?BottomRight:?TPoint);
???end;
是不是也是一樣的呢?
?
?
?
變體記錄得作用
?
(1)節約空間。對于那些要根據條件而決定是否存儲得類型,完全可以利用變體記錄來達到節約空間得效果。例如,一個公司的員工薪水可以是月薪、年薪等方式,那么并沒有必要在記錄中都分配空間而又用不到。
?
(2)類型的轉換。例如,如果有一個64位的整數類型作為變體的第一個字段,一個32位的整數Integer類型作為另一個變體的第一個字段,那么可以向64字段賦值然后以整數Integer字段讀出其前32位
?
?
?
?
?
//假如有這樣一個員工登記表
type?TpersonRec?=?record
????ID:?Integer;????????????{員工編號}
????case?Boolean?of?????????{根據分類}
??????True:??(A:?Cardinal);?{如果是股東,?登記年薪}
??????False:?(B:?Word);?????{如果不是,???登記日薪}
??end;
var
??personRec:?TpersonRec;
begin
??{先算一算這個結構的大小:
????ID?是?Integer??類型,?應該是???4??字節大小;
????A??是?Cardinal?類型,?也應該是?4??字節大小;
????B??是?Word?????類型,?應該是???2??字節大小;
????合計為????????????????????????10?個字節.
??}
??{可事實,?TpersonRec?只有?8?個字節}
??ShowMessage(IntToStr(SizeOf(TpersonRec)));?{8}
?
??{
????原因是:?字段?A?和?字段?B?公用了一個儲存空間;
????當然這個儲存空間得依著大的,?是?Cardinal?的尺寸?4?個字節.
??}
?
//賦值測試:
??personRec.ID?:=?110;
??personRec.A??:=?100000;?{一看就知道是個股東}
?
//取值:
??ShowMessage(IntToStr(personRec.A));?{100000;?這不可能有錯,?十萬大洋}
?
//但是:
??ShowMessage(IntToStr(personRec.B));?{34464??!?難道這是工人的日薪嗎?}
??{
????首先,?A?和?B?兩個字段占用同一個空間,?給其中一個賦值,?另一個當然也就有值了;
????但因為數據類型的容量不同,?它們的值有可能是不一樣的.
????在很多情況下,?我們可能根本不去理會另一個值,?但如果的確需要呢?
????看下一個例子:
??}
end;
?
?
?
type
??TpersonRec?=?record
????ID:?Integer;
????case?tag:?Boolean?of????{在這里加了一個?tag?變量}
??????True:??(A:?Cardinal);
??????False:?(B:?Word);
??end;
var
??personRec:?TpersonRec;
begin
??{我們可以用?tag?變量來區分,?記錄中變體部分的值到底是誰的,?譬如:}
??personRec.ID??:=?110;
??personRec.tag?:=?True;
??personRec.A???:=?100000;?{股東的的年薪}
?
??personRec.ID??:=?111;
??personRec.tag?:=?False;
??personRec.B???:=?100;????{工人的日薪}
end;
?
?
?
//最經典的變體結構莫過于?Delphi?定義的?TMessage?結構了,?兩組數據分分合合都是一體,?多么巧妙啊!
?
TMessage?=?packed?record
????Msg:?Cardinal;
????case?Integer?of
??????0:?(
????????WParam:?Longint;
????????LParam:?Longint;
????????Result:?Longint);
??????1:?(
????????WParamLo:?Word;
????????WParamHi:?Word;
????????LParamLo:?Word;
????????LParamHi:?Word;
????????ResultLo:?Word;
????????ResultHi:?Word);
??end;
**************理論區?end??*********************
?
?
**************演示區?start*********************
type
??TDerivativeAttributeValue?=?packed?record
????case?Integer?of
??????0:?(nValue:?Integer);
??????1:?(?wValueLo?:?SmallInt;
???????????case?Integer?of
?????????????0:(wValueHi:?SmallInt);
?????????????1:(btValueHiLo?:?ShortInt;
????????????????btValueHiHi?:?ShortInt;);
?????????);
??end;
?
?
//?將int轉換成二進制形式
Function?Str_IntToBin(Int:?LongInt;?Size:?Integer):?String;
Var
??i:?Integer;
Begin
??If?Size?<?1?Then?Exit;
??For?i?:=?Size?Downto?1?Do
????Begin
??????If?Int?And?(1?Shl?(Size?-?i))?<>?0?Then
????????Result?:=?'1'?+?Result
??????Else
????????Result?:=?'0'?+?Result;
????End;
End;
?
?
procedure?TForm1.btn3Click(Sender:?TObject);
var
??X:?TDerivativeAttributeValue;
?
begin
??{
???1:?給?nvalue賦值??訪問其他位?這樣的使用?一般作用不大?重點在第二個
??}
??X.nValue?:=?2147483646;
??ShowMessage(IntToStr(x.nValue)?+?'->'?+?Str_IntToBin(x.nValue,?32));
??ShowMessage(IntToStr(x.wValueLo)?+?'->'?+?Str_IntToBin(x.wValueLo,?16));
??ShowMessage(IntToStr(x.wValueHi)?+?'->'?+?Str_IntToBin(x.wValueHi,?16));
??ShowMessage(IntToStr(x.btValueHiLo)?+?'->'?+?Str_IntToBin(x.btValueHiLo,?8));
??ShowMessage(IntToStr(x.btValueHiHi)?+?'->'?+?Str_IntToBin(x.btValueHiHi,?8));
?
?
??{
???2:?給?其他的分管符號賦值(各個分管符號有各自的作用)??將nValue數據保存在文件中
??}
??x.wValueLo?:=?137;
??x.btValueHiLo?:=?37;
??x.btValueHiHi?:=?13;
??ShowMessage(IntToStr(x.nValue)?+?'->'?+?Str_IntToBin(x.nValue,?32));
end;
?
?
**************演示區?end??*********************
轉載于:https://www.cnblogs.com/bbnn38/p/3341835.html
總結
以上是生活随笔為你收集整理的变体类的使用 package record case【转载】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 好听的工作室名字大全
- 下一篇: 词语繁华过后下一句是什么啊?