看不懂的定义 ( 积分: 22 )

  • 主题发起人 主题发起人 ykjt
  • 开始时间 开始时间
Y

ykjt

Unregistered / Unconfirmed
GUEST, unregistred user!
hostent = record
h_name: PChar;
h_aliases: ^PChar;
h_addrtype: Smallint;
h_length: Smallint;
case Byte of //byte是谁的取值?
0: (h_addr_list: ^PChar);
1: (h_addr: ^PChar)
end;
THostEnt = hostent;
 
hostent = record
h_name: PChar;
h_aliases: ^PChar;
h_addrtype: Smallint;
h_length: Smallint;
case Byte of //byte是谁的取值?
0: (h_addr_list: ^PChar);
1: (h_addr: ^PChar)
end;
THostEnt = hostent;
 
原理性的东西欧一向很弱,看高人的回答

-------------------------转自网络
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1129029
咳,这个问题应该很容易的。不过还是说一下,省得你化这许多力气在这里。
TMessage = packed record
Msg: Cardinal; // 消息ID
case Integer of // 此处的Integer针对什么来说的?
0: ( // 什么时候用到?
WParam: Longint; // wparam 在MFC中是什么意思?
LParam: Longint; // lparam 在MFC中是什么意思?
Result: Longint);
1: ( // 什么时候用到?
WParamLo: Word;
WParamHi: Word;
LParamLo: Word;
LParamHi: Word;
ResultLo: Word;
ResultHi: Word);
end;
就是告诉编译器,TMessage这个数据类型是这样的:
00~03:Msg: Cardinal;
04~05:WParamLo: Word;--1
06~07:WParamHi: Word;--2; 1,2和起来是: WParam: Longint
08~09:LParamLo: Word;--3
0A~0B:LParamHi: Word;--4; 3,4和起来是: LParam: Longint
0C~0D:ResultLo: Word;--5
0E~0F:ResultHi: Word;--6; 5,6和起来是:Result: Longint
你即可以用WParamLo,WParamHi,LParamLo,LParamHi,ResultLo,ResultHi来访问04~0F的数据
也可以用WParam,LParam,Result来访问04~0F的数据。
你想怎么访问都可以。就是使你用起来更方便。

比如有一个记录:
type
MyRecord=Record
a:Integer;
Data:Integer
end;
比如,我想访问Data的高16位和低16位,就可以这样定义:
type
MyRecord2=Record
a:Integer;
case integer of
0:(Data:Integer);
1:(DataHi,DataLow:Word) ;
end;
其实,MyRecord2和MyRecord的内存使用是完全一样的,但你可以通过
DataHi,DataLow来访问Data的高16位和低16位。
具体的实现细节,我希望你自己去找吧!


DarwinZhang (2002-05-31 19:07:00)
综合上面的,不难给出:
TMessage2 = packed record
Msg: Cardinal;
WParam: Longint;
LParam: Longint;
Result: Longint;
end;
和TMessage在具体的物理内存上是一样的。
有的时候可能不一样,比如:
type
TestRec=Record
a:Byte;
case integer of
0:(b:Integer);
1:(c,d,e:Word);//多出一个e,内存就会强制加大
end;
TestRec2=Record
a:Byte;
b:Integer;
end;
TestRec和TestRec2就不相等。

--------------------------------------------------看帮助
A record type can have a variant part, which looks like a case statement. The variant part must follow the other fields in the record declaration.
To declare a record type with a variant part, use the following syntax.

type recordTypeName = record

fieldList1: type1;
...
fieldListn: typen;
case tag: ordinalType of
constantList1: (variant1);
...
constantListn: (variantn);
end;

The first part of the declaration梪p to the reserved word case梚s the same as that of a standard record type. The remainder of the declaration梖rom case to the optional final semicolon梚s called the variant part. In the variant part,

tag is optional and can be any valid identifier. If you omit tag, omit the colon (:) after it as well.
ordinalType denotes an ordinal type.
Each constantList is a constant denoting a value of type ordinalType, or a comma-delimited list of such constants. No value can be represented more than once in the combined constantLists.
Each variant is a comma-delimited list of declarations resembling the fieldList: type constructions in the main part of the record type. That is, a variant has the form

fieldList1: type1;

...
fieldListn: typen;

where each fieldList is a valid identifier or comma-delimited list of identifiers, each type denotes a type, and the final semicolon is optional. The types must not be long strings, dynamic arrays, variants (that is, Variant types), or interfaces, nor can they be structured types that contain long strings, dynamic arrays, variants, or interfaces; but they can be pointers to these types.

Records with variant parts are complicated syntactically but deceptively simple semantically. The variant part of a record contains several variants which share the same space in memory. You can read or write to any field of any variant at any time; but if you write to a field in one variant and then to a field in another variant, you may be overwriting your own data. The tag, if there is one, functions as an extra field (of type ordinalType) in the non-variant part of the record.

Variant parts have two purposes. First, suppose you want to create a record type that has fields for different kinds of data, but you know that you will never need to use all of the fields in a single record instance. For example,

type

TEmployee = record
FirstName, LastName: string[40];
BirthDate: TDate;
case Salaried: Boolean of
True: (AnnualSalary: Currency);
False: (HourlyWage: Currency);
end;

The idea here is that every employee has either a salary or an hourly wage, but not both. So when you create an instance of TEmployee, there is no reason to allocate enough memory for both fields. In this case, the only difference between the variants is in the field names, but the fields could just as easily have been of different types. Consider some more complicated examples:

type

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 = record
case TShapeList of
Rectangle: (Height, Width: Real);
Triangle: (Side1, Side2, Angle: Real);
Circle: (Radius: Real);
Ellipse, Other: ();
end;

For each record instance, the compiler allocates enough memory to hold all the fields in the largest variant. The optional tag and the constantLists (like Rectangle, Triangle, and so forth in the last example above) play no role in the way the compiler manages the fields; they are there only for the convenience of the programmer.
The second reason for variant parts is that they let you treat the same data as belonging to different types, even in cases where the compiler would not allow a typecast. For example, if you have a 64-bit Real as the first field in one variant and a 32-bit Integer as the first field in another, you can assign a value to the Real field and then read back the first 32 bits of it as the value of the Integer field (passing it, say, to a function that requires integer parameters).
 
这和变体具体是如何使用?
 
类似C++的union联合定义,参阅一下,就是一个变体结构,根据需要调用不同的结构参数,以简化内存分配。
 
TSockAddrIn = packed record

case Integer of
0: (sin_family: u_short;
sin_port: u_short;
sin_addr: TInAddr;
sin_zero: array[0..7] of Char);
1: (sa_family: u_short;
sa_data: array[0..13] of Char)

end;

//上面是典型的联合定义,你运用该结构时会有所体会。
例如:
type
AA=record
case Integer of
0:(a,b:BYTE);
1:(c:WORD);
end; //注意AA的尺寸是2,而不是4。
var
a:AA;
a.b :=$1;
a.a :=$0;
那么a.c则=$0100;
 
<一>记录(类似于其它语言中的结构)表示不同种类的元素的集合,每个元素称为“字段”,声明记录类型时要为每个字段指定名称和类型。声明记录的语法为

type recordTypeName = record

fieldList1:type1;

fieldList2:typen;

end

<二>一个记录类型能拥有变体部分(看起来象case语句),在声明中,变体部分必须跟在其它字段的后面。要声明一个变体记录,使用如下语法:

type recordTypeName = record

fieldList1:type1;

fieldListn:typen;

case tag : ordinaltypeof

constantList1:(Variant1);

constantListn:(Variantn);

end;

声明的前面部分(直到关键字case)和标准记录类型一样,声明的其余部分(从case到最后一个可选的分号)称为变体部分,在变体部分

1tag是可选的,它可以是任何有效标识符。如果省略了tag,也要省略它后面的冒号。

2ordinalType表示一种有序类型。

3每个constantList表示一个ordinalType类型的常量,或者用逗号隔开的常量序列。在所有的常量中,一个值不能出现多次。

4每个Variant是一个由逗号隔开的、类似于fieldList:type的声明列表,也就是说,Variant有下面的形式:

fieldList1:type1;

fieldListn:typen;

这里,每个fieldList是一个有效标志符,或是由逗号隔开的标志符列表,每个type表示一种类型,最后一个分号是可选的。这些类型不能是长字符串、动态数组、变体类型或接口(都属于动态管理类型),也不能是包含上述类型的结构类型,但它们可以是指向这些类型的指针。

变体记录类型语法复杂,但语义却很简单:记录的变体部分包含几个变体类型,它们共享同一个内存区域。你能在任何时候,对任何一个变体类型的任何字段读取或写入,但是,当改变了一个变体的一个字段,又改变了另一个变体的一个字段时,你可能覆盖了自己的数据。如果使用了tag,它就像记录中非变体部分一个额外的字段,它的类型是ordinalType。

变体部分有两个目的。1当记录中字段有不同类型数据(一个实例中不需要所有的字段),所以,当创建实例时,没必要为每个字段都分配内存。

原因二:可将同一个数据当作不同的类型进行处理,即使在编译器不允许类型转换的场合。比如:在一个变体类型中,它的第一个字段是64位实数,在另一个变体类型中,第一个字段是32位整数,你可以把一个值赋给实数,然后再当作整数来读取它的前32位值。
 
如果使用了tag,它就像记录中非变体部分一个额外的字段,它的类型是ordinalType。
=============================
tag(字段1)
tag(字段2)
这样 '字段2' 就不会覆盖 '字段1'的内存空间,就象非变体一样。这样理解对吗?
 
说白了,你需要以下情况:
1、当为A情况,记录为Integer数据。
2、当为B情况,记录为字符数据。
type
AA=record
case Integer of
0:(nFlag:Integer);
1:(nStr:array [0..100] of char)
end;
你要记录数据就:AA.nFlag :=???
要记录字符就:AA.nStr :=???
调用数据也要根据情况调用AA.nFlag或AA.nStr;
=====================================================
初始化AA时会分配100个字节,即nFlag与nStr共用100个字节,当nStr赋值后,nFlag也是有值的,它的值就是nStr的前4个字节
 
后退
顶部