delphiのレコードとバリアントレコードはhttps://blog.csdn.net/yt_maomao/article/details/36631133

// Integer型は正確に4バイト、ShortInt型は1バイトですが、Windowsのメモリは4バイトが割り当てられています
// //これは実際には4バイトです。このレコードのサイズは、SizeOfで確認できます8バイト、ただし
スペースを
浪費しますが、スピードアップします(Windowsのメモリ割り当てにおける境界整列の原則)TPerson = record
Age:Integer;
Sex:ShortInt;
end;
TPackedPerson = packed record
Age:Integer;
Sex: ShortInt; //パックされたレコードを使用すると、このレコードのサイズがSizeof;で5バイトであることがわかります;
end;

TEmployee =レコード
ID:Integer; //整数は4バイト
ケース
0の整数:(YearMoney:Integer); / / YearMoneyとMonthMoneyは、最大メモリ割り当てに従ってメモリを共有します
1:(MonthMoney:ShortInt); //レコードのサイズは8バイトです
end;

TTagEmployee =レコード
ID:Integer;
ケースGrade:Integer of // Grade変数が追加されます
0:(YearMoney:Integer); //最大メモリ割り当てに応じて、YearMoneyとMonthMoneyはメモリを共有します
1:(MonthMoney:ShortInt); //レコードのサイズは12バイト(ID + Grade + YearMoney)
end;

 

1. DELPHIでは、recordキーワードを使用してレコードを示します。場合によっては、パックされたレコードで宣言されたレコードも表示されます。2つの違いは、保存方法にあります。ウィンドウでは、メモリ割り当ては一度に4バイトであり、Packedはメモリをバイト単位で適用して割り当てますが、ポインターを見つけるために追加の時間が必要になるため、処理が遅くなります。したがって、Packedを使用しない場合、Delphiは一度に4バイトの形式でメモリに適用するため、変数の幅が4バイトでない場合も、4バイトを占有します。これにより、一部のスペースが無駄になりますが、効率が向上します。

2.バリアントレコーディングのルール:

       (1)Long String、WideString、Dynamic Array、およびInterfaceのサイズはすべてポインタサイズで、OleVariantは実際にはCOM SDKのVARIANT構造体であり、サイズは16バイトです。ただし、Object Pascalでは、これらはすべて自動的にファイナライズされる必要があります。バリアントパーツに表示される場合、コンパイラはそれらがファイナライズされる必要があるかどうかを知ることができません。なぜなら、現在格納されているタイプがわからないため、変数に表示されないためです。本文レコードタイプで、または同様の文字列[10]を使用して定義します。

(2)すべてのバリアントフィールドはメモリのセクションを共有し、共有メモリのサイズは最大のバリアントフィールド(「最長」の変数)によって決定されます。

(3)タグが存在する場合、それはレコードのフィールドでもあります。タグがない場合もあります。 

(4)レコードのバリアント部分の条件フィールドは、順序付きの型でなければなりません。Caseに続く型は、ブール、整数などの順序付きの型でなければなりません。

(5)レコードタイプには、Caseステートメントのようなバリアントパーツを含めることができますが、最終的な終わりはありません。バリアントパーツは、レコード内の他のフィールドの宣言の後にある必要があります。

3.最も古典的なバリアントレコードであるDelphiのTMessage構造:

バリアントレコードとも呼ばれるバリアント構造は、比較的複雑な概念であり、専門家はその使用を推奨していません。

 

最大の符号なし整数(Cardinal)は4294967295、サイズは4バイト、バイナリ表現は 
11111111 11111111 11111111 11111111
下位バイトの値は11111111で、10進数の255です。

//テスト:
var
c:Cardinal;
begin
c:= 4294967295;
ShowMessage(IntToStr(Lo(c))); {will show:255; Lo is the function to get the low byte value}
end;
Byte型の最大値それは255であり、そのサイズは2バイトで表される1バイトです:11111111
タイプCardinalの値がタイプByteの値に割り当てられる場合、ByteはCardinalの最下位バイトのみを使用します
。//テスト:
var
c:カーディナル;
b:バイト;
開始
c:= 4294967295;
b:= c;
ShowMessage(IntToStr(b)); {255}

c:= 258; {バイナリ表現:00000000 00000000 00000001 00000010}
b:= c; {bはのみ取得:00000010}
ShowMessage(IntToStr(b)); {2}
end;
これは、構造が格納されるときにCardinalを格納できるスペースと考えることができるかどうかです。もちろん、Byte値を置くこともできます。
これが値はどちらかです。2つの保管スペースはまったく必要ありません。
これは、Delphiのデザインバリアントレコードの本来の意図であると思います。
//そのような従業員登録フォーム
タイプがある場合
TpersonRec =レコード
ID:整数; {従業員番号}
ケースブールの{分類に従って}
True:(A:Cardinal); {それが株主の場合、年収を登録}
False:(B:Word ); {そうでない場合、日給を登録}
end;
var
personRec:TpersonRec;
begin
{この構造体のサイズを最初に計算:
IDは整数型、サイズは4バイト、
Aはカーディナル型、また4ワードセクションサイズ;
BはWordタイプであり、サイズは2バイトで、
合計は10バイトです。
}
{実際には、TpersonRecは8バイトのみです}
ShowMessage(IntToStr(SizeOf(TpersonRec))); {8}
{
理由はい:フィールドAとフィールドBはストレージスペースを共有します。
もちろん、このストレージスペースはカーディナルサイズの4バイトである大きなサイズに依存します。
}
//割り当てテスト:
personRec.ID:= 110;
personRec.A:= 100000; {一目でわかる株主です}
//値:
ShowMessage(IntToStr(personRec.A)); {100000;これは間違いありません、10万の海}
//しかし:
ShowMessage(IntToStr(personRec.B)); {34464 ?!これは労働者の日給ですか? }
{
最初に、2つのフィールドAとBは同じスペースを占め、一方には値があり、もう一方には値があります
が、データ型の容量が異なるため、それらの値は異なる場合があります。
多くの場合、次に、別の値はまったく気にしないかもしれませんが、それが本当に必要な場合は
、次の例を見てください
}
end;

type
TpersonRec = record
ID:Integer;
case tag:Boolean of {Here added a tag variable}
True: (A:Cardinal);
False:(B:Word);
end;
var
personRec:TpersonRec;
begin
{タグ変数を使用して、レコードのバリアントパーツの値を区別できます例:
personRec.ID: = 110;
personRec.tag:= True;
personRec.A:= 100000; {年次株主の給与}
personRec.ID:= 111;
personRec.tag:= False;
personRec.B:= 100; {worker's daily salary}
end;

//最も古典的なバリアント構造はDelphiによって定義されたTMessage構造であり、2つのデータグループがすべて1つにまとめられています。 !どのように巧妙なああ
TMessage =録音詰め
メッセージ:枢機卿;
の場合整数
0:(
WPARAM:倍長整数;
LPARAM:倍長整数;
結果:倍長整数);
1:。(
WParamLo:ワード;
WParamHi:ワード;
LParamLo:ワード;
LParamHi:Wordを。
ResultLo:Word;
ResultHi:Word);
end;

レコード(レコード)
レコード(他の言語の構造と同様)は、さまざまな種類の要素のコレクションを表します。各要素は「フィールド」と呼ばれ、レコードタイプ
宣言するときは、各フィールドの名前とタイプを指定する必要があります。レコードを宣言するための構文は、
タイプrecordTypeName = record
fieldList1:type1;
...
fieldListn:typen;
end
ここで、recordTypeNameは有効な識別子であり、各タイプはタイプを表し、各fieldListは有効な識別子であるか
、カンマで区切られていますオープンIDシーケンスの場合、最後のセミコロンはオプションです。(どのセミコロンですか?最後のフィールドですか、それとも終了後ですか?)たとえば
、次のステートメントはレコードタイプTDateRecを宣言します:
タイプ
TDateRec =レコード
年:整数;
月:(1月、2月、3月、4月、5月、 6月、7月、8月、9月、10月、11月、12月);
日:1..31;
終了;
TDateRecには、整数型年、列挙型月、および別のサブ境界型の3つのフィールドが含まれます。日。標準
カイフー年、月、日、彼らは変数のように振る舞い、TDateRecフィールドです。この宣言では、Year、Month、Dayの
メモリ割り当てられません。次のようにインスタンス化されたときにのみ割り当てられます
。var Record1、Record2:TDateRec;
上記の変数宣言は、Record1とRecord2という2つのTDateRecインスタンスを作成します。
レコード名を修飾子として使用し、フィールド名でフィールドにアクセスできます:
Record1.Year:= 1904;
Record1.Month:= Jun;
Record1.Day:= 16;
またはwithステートメントを使用:
with Record1 do
begin
Year:= 1904;
月:= Jun;
日:= 16;
end;
これで、Record1の値をRecord2にコピーできます:
Record2:= Record1;
フィールド名のスコープはレコード自体に制限されているため、フィールド名と他の変数との競合について心配する必要はありません。
レコードタイプを定義する代わりに、変数宣言で直接レコード...構成を使用できます。
レコードタイプを定義することに加えて、レコード...を使用して直接宣言変数を構成することもできます
。var S:レコード
名:文字列;
年齢:整数;
end;
ただし、これは型宣言を再利用することを許可せず、宣言された型は、それら(レコード)が
まったく同じ構造を持っている場合でも、代入互換ではありません

レコードのバリアントパーツ
レコードタイプには、バリアントパーツを含めることができます。これは、caseステートメントのように見えます。宣言では、バリアントパーツは他のフィールドの後に続く必要があります。
バリアントレコードを宣言するには、次の構文を使用します。

type recordTypeName = record
fieldList1:type1;
...
fieldListn:typen;
case tag:ordinalType of
constantList1:(Variant1);
...
constantListn:(Variantn);
end;
前の宣言部分(キーワードケースまで)と標準レコードタイプは同じです。残りの宣言(大文字小文字の区別から最後のオプションの
セミコロンまで)はバリアント部分と呼ばれます。バリアント部分では、
 タグはオプションであり、任意の有効な識別子にすることができます。タグを省略する場合は、その後のコロン(:)も省略します。
 ordinalTypeは、順序付けられたタイプを表します。
 各constantListは、タイプordinalTypeの定数、またはコンマで区切られた定数のシーケンスを表します。すべての定数の中
で、値は複数回出現することはできません。
 各バリアントは、コンマで区切られた宣言のリストで、fieldList:型に似ています。つまり、バリアントの
形式は次のとおりです:
fieldList1:type1;
...
fieldListn:typen;
ここで、各fieldListは有効なフラグです文字、またはカンマで区切られた識別子のリスト。各タイプはタイプを表し、
最後のセミコロンはオプションです。これらの型は、長い文字列、動的配列、バリアント型、またはインターフェースにすることはできません(すべて動的管理に属します)
管理タイプ)は、上記のタイプを含む構造タイプにすることはできませんが、これらのタイプへのポインターにすることができます。
複雑なバリアントレコードタイプの構文、セマンティクスが、非常にシンプル:バリアントレコード部分がバリアントのいくつかのタイプが含まれ、それらが同じメモリ領域を共有
ドメインを。バリアントタイプのフィールドはいつでも読み書きできますが、バリアントの
フィールドと別のバリアントのフィールドを変更すると、上書きされる場合があります自分のデータ。記録好きなタグ、もし
型ordinalTypeのある身体の余分なフィールドの-invariant一部を。
バリアント部分には2つの目的があります。まず、あなたがそのようなレコードを作成するとします。それは異なるタイプのデータがある分野だが、あなたは、知っている中
(レコード)の場合、あなた決して必要のようなすべてのフィールド、:
タイプの
TEmployee =録音
のFirstName、LastNameの:文字列[ 40];
BirthDate:TDate;
case Salaried:Boolean of
True:(AnnualSalary:Currency);
False:(HourlyWage:Currency);
end;
ここでの考え方は、各従業員が年収または時給のいずれかであり、両方ではないということですそれらすべて。したがって、TEmployeeの
インスタンスを作成するときに、各フィールドにメモリを割り当てる必要はありません。上記の場合、バリアント間の唯一の違いはフィールド名ですが、より単純な
ケースは、フィールドの型が異なることです。より複雑な例を見てみましょう。
タイプ
TPerson = record
FirstName、LastName:string [40];
BirthDate:TDate;
case Citizen:Boolean of
True:(Birthplace:string [40]);
False:(Country:string [20];
EntryPort:string [20];
EntryDate、ExitDate: TDate);
end;
type
TShapeList =(Rectangle、Triangle、Circle、Ellipse、Other);
TFigure =レコード
ケースTShapeList of
Rectangle:(Height、Width:Real);
Triangle:(Side1、Side2、Angle:Real);
Circle: (半径:実数);
楕円、その他:();
終了;
レコード型の各インスタンスに対して、コンパイラは最大のバリアント型のすべてのフィールドに対応するために十分なメモリを割り当てます。オプションのタグと
(など長方形、三角形、上記の例のように)constantListsは、コンパイラ管理分野に影響を与えない、彼らは唯一のためのものである
プログラマの利便性。
バリアントレコードを使用する2つ目の理由は、コンパイラーがクラスを許可していない場合でも、同じデータを異なる型として処理できることです
タイプ変換の機会。たとえば、バリアント型では、最初のフィールドは64ビットの実数であり、別のバリアント型では、最初の
フィールドは32ビットの整数であり、実数(フィールド)に値を割り当てることができます。これを整数として使用して、最初の32ビット値を読み取ります(たとえば、
整数パラメーターを必要とする関数に渡します)。
————————————————
著作権声明:この記事はCSDNブロガー "_毛毛_"のオリジナル記事です。CC4.0 BY-SA著作権契約に従ってください。元のソースリンクを添付して転載してくださいこのステートメント。
元のリンク:https://blog.csdn.net/yt_maomao/article/details/36631133

おすすめ

転載: www.cnblogs.com/QuincyYi/p/12730132.html