type
TVarRec=record
case Byte of
vtInteger: (VInteger:Integer;VType:Byte);
vtBoolean: (VBoolean:Boolean);
...
end;
请问其中case后面byte是指什么?整个这个可变记录类型该如何理解?有时在程序中看到
type
TVarData=pack record
case Integer of
varSmallint: (VSmallint:Smallint);
...
end;为什么case of语句中间是integer、byte?这是两种类型呀?
不是说case of语句中间应该是一个有序的变量吗?怎么会是两个类型?
不能理解,还请大侠高手指点,谢谢!
TVarRec=record
case Byte of
vtInteger: (VInteger:Integer;VType:Byte);
vtBoolean: (VBoolean:Boolean);
...
end;
请问其中case后面byte是指什么?整个这个可变记录类型该如何理解?有时在程序中看到
type
TVarData=pack record
case Integer of
varSmallint: (VSmallint:Smallint);
...
end;为什么case of语句中间是integer、byte?这是两种类型呀?
不是说case of语句中间应该是一个有序的变量吗?怎么会是两个类型?
不能理解,还请大侠高手指点,谢谢!
解决方案 »
- dll中如何定义变参,不够可以加分,绑定有分
- pos58打印机定向打印,奖励100
- 关于主从表的保存和子表在的dbgrideh中的显示问题
- 寻找一个将某word文档和JPG图像加入ACCESS数据库的例子
- dbimage来显示Access表里的图片
- 关于动态创建计算字段!200分进者有分
- 关于sqlserver2000的安装问题!
- form2:=tform2.create(self)这句语句的作用,马上给分
- 请问谁有关于网吧的资料,最好有源程序就好拉,.......
- 关于TWebBrowser的问题
- 请问如何在文件流中搜索关键字,如使用TFileStream打开一个文件,想在这个中搜索1234,并且指针也移运到这里。如何做呢?代码如下,请指
- MSCOMM控件的错误,请指教。
type
TVarRec=record
case Byte of
vtInteger: (VInteger:Integer;VType:Byte);
vtBoolean: (VBoolean:Boolean);
...
end;表示TVarRec记录即可以看作是VInteger:Integer;VType:Byte, 也可以看作为VBoolean:Boolean的存放,但两者只能选一。Byte只是一个无名标识,并没有太大的意义。
里面的vtInteger 肯定是一常量
inaddr与outaddr有什么区别呢?inaddr = record
case integer of
0: (s1: Integer);
1: (s2: Integer);
2: (s3: String[10]);
end; outaddr=record
s1:integer;
s2:integer;
s3:string;
end;
var
Form1: TForm1;
a:in_addr;
b:outaddr;implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
begin
a.S1:=1;
a.S2:=2;
a.S3:='abcd';
b.s1:=1;
b.s2:=2;
b.s3:='abcd'; showmessage(inttostr(a.S1)+#13#10+inttostr(a.S2)+#13#10+a.S3);
showmessage(inttostr(b.s1)+#13#10+inttostr(b.s2)+#13#10+b.s3);
end;
inaddr = record
case integer of
0: (s1: Integer);
1: (s2: Integer);
2: (s3: String[10]); // 必须是
end;
联合结构体必须是固定大小的 不然系统不好给你分配内存,所以需要定义为string[10]表示定义10BYTE大小的字符串。。而 outaddr=record
s1:integer;
s2:integer;
s3:string;
end;
则因为是普通的结构体 允许不定大小的内存还有就去画一画里面的内存布局就OK了。。
case integer of
0: (s1: Integer);
1: (s2: Integer);
2: (s3: String[10]); // 必须是
end;
上面case语句中,请问0,1,2是否只是起到一个序号的作用?在调用时,和普通的结构体是一样的调用,只是内存分配不同。
是这样吗?
0: (s1: Integer);
1: (s2: Integer);
2: (s3: String[10]); // 必须是
end;
上面case语句中,请问0,1,2是否只是起到一个序号的作用?
0, 1, 2表示三种情况,就是说这个结构体允许三种数据结构共存 就像一个瓶子里面,可是同时放三样东西 当然他们只占一个瓶子的空间 不过一般来说 有意义的数据只有一个<这要看自己去分析>在调用时,和普通的结构体是一样的调用,只是内存分配不同。
是这样吗?
分配内存 值得系统的分配不一样而已,,调用 你上面都已经调用了
TPerson = record
case Citizen: Boolean of
True: (Birthplace: string[10]);
False: (Country: string[5]);
end;像上面case语句中citizen这个变量有何作用呢?
是不是只是起到一个标识作用?让程序员可以知道这个变体部分内容的含义?
大侠,还请您指点,谢谢!
这个变量有没有都可以case Boolean of // 也可以的
主要解答者: plainsong 提交人: FrameSniper
感谢: lxpbuaa、FrameSniper、jacky_shen
审核者: hthunter 社区对应贴子: 查看 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;
上面这个记录类型里的Integer是从哪里来的?
想想总觉得有些奇怪,对于一个记录类型来说,它的字段是可以为任意数据类型的,对记录类型的数据进行操作都是通过这样来进行的:MyRecord.Field,好像不能传递参数,那么这个Integer在那里呢,是在对记录进行操作的函数或过程内吗?
---------------------------------------------------------------
以下文字摘自拙作《Delphi精要》:
一个变体记录典型的定义如下:
type recordTypeName = record
fieldList1: type1;
...
fieldListn: typen;
case tag: ordinalType of
constantList1: (variant1);
...
constantListn: (variantn);
end;
其中case到结尾部分定义了多个变体字段。所有变体字段共享一段内存,换句话说,如果你给constantList1赋值,那么constantList2-constantListn也就被赋了值。至于这些变体字段返回什么值,则是由它们的类型决定。程序根据tag的值决定应该使用constantList1-constantListn中的哪个字段。例如:
type
TDataConv = record
case T: Boolean of
True: (I: Byte);
False: (B: Boolean;);
end;
var
D: TDataConv;
begin
D.I := 1; {此时D.B=True,因为I和B这两个变体字段共享一段内存}
end;
使用变体记录时要注意:
(1)变体字段不能是编译时大小不能确定的类型,如long strings、dynamic arrays、variants、interfaces等。
(2)所有变体字段共享一段内存。而共享内存的大小则由最大变体字段决定。
(3)当tag存在时,它也是记录的一个字段。也可以没有tag。
再看Messages单元定义的消息类型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;
case部分并没有tag字段,接下来的0和1只是为了给变体字段分组,0部分的三个字段和1部分的六个字段共享一段内存。这段内存大小是4(Longint即Integer,占用4个字节)*3=12个字节。一个Word占用2个字节。我们知道一个32位整数在内存中是高字节在后,低字节在前,因此,WParamLo被对应到WParam的低16位,WParamHi被对应到WParam的高16位。依次类推。换句话说,通过WParamLo可以取得WParam的低16位,而通过WParamHi可以取得WParam的高16位。
------------------------------------
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
------------------------------------
---------------------------------------------------------------
天啊,都这么多人,说的很详细了,不过一楼的一个地方说的不对
记录的变体部分的条件域必须是有序类型,而不是什么可以计算大小的类型,另外这句话表达不对----“如果你给constantList1赋值,那么constantList2-constantListn也就被赋了值”,记录的变体部分的实际类型是Variant类型,所以这里可以定义成任何类型,同时空间大小服从所有变体类型中占用空间最大的那个,任何时刻变体部分的类型都是唯一的,其他类型此时没有意义,也不存在,所以不能说一个被赋值,所有的全部赋予了值!
---------------------------------------------------------------
一不小心提交了。继续……
Long String、WideString、Dynamic Array、Interface的大小都是指针大小,OleVariant其实就是COM SDK中的VARIANT结构,大小是16字节。但在Object Pascal中它们都需要自动终结化,如果它们出现在variant part中,编译器就无法知道它们是否应该进行终结化--因为不知道当前存储的是哪种类型。
如果学过C语言,对variant part应该很好理解,它就相当于union。只是多了些限制:每个记录体只能有一个variant part;只能出现在记录体的结尾;不允许出现自动终结化的类型。
---------------------------------------------------------------
记录中的变体部分
记录类型中可以含有变体部分,有点象case语句。变体部分必需在记录中其他字段的声明之后。
声明含有变体部分的记录类型,语法如下:
type recordTypeName = record
fieldList1: type1;
...
fieldListn: typen;
case tag: ordinalType of
constantList1: (variant1);
...
constantListn: (variantn);
end;
在保留字case之前的声明部分与标准记录类型中的声明相同。剩余从case到end之前最后一个可选的分号(;)之间叫做变体部分。在变体部分中:
· tag是可选的,并且可以是任意有效的标识符。如果忽略tag,那么也要同时忽略紧随其后的冒号(:)。
· ordinalType表示一个序数类型。
· 每个constantList都是一个表示ordinalType类型的常量,或者逗号隔开的此类常量列表。在当前变体部分声明中,对于所有的constantLists,同一个值最多只能出现一次。
· 每个variant都是一个逗号隔开的声明列表,这与记录类型主要部分中的fieldList: type结构相似。也就是说,variant具有如下形式
fieldList1: type1;
...
fieldListn: typen;
这里,每个fieldList是一个有效标识符或者逗号隔开的标识符列表,每个type代表一个类型,最后的分号是可选的。所有的类型(types)都不能是长串、动态数组、变体(即Variant类型)或接口,也不能是包含长串、动态数组、变体(即Variant类型)或接口的结构类型;但可以是指向这些类型的指针。
含有变体部分的记录在语句构成上比较复杂,但在语义上比较简单,具有欺骗性。记录中的变体部分包含几个变体,在内存中它们共享相同的空间。可以在任何时候对记录中任何变体的任何字段读或写;但如果在一个变体中写一个字段并且在另一个变体中写另一个字段,那么后面的写操作可能覆盖前面写入的数据。对于Tag,如果存在,那么将作为记录中的非变体部分,被视为额外的字段(其类型是ordinalType)。
变体部分有两种用途。首先,假设要创建一个记录类型,它有不同数据种类的字段,但不需要在单个记录实例中使用全部数据。例如,
type
TEmployee = record
FirstName, LastName: string[40];
BirthDate: TDate;
case Salaried: Boolean of
True: (AnnualSalary: Currency);
False: (HourlyWage: Currency);
end;
这里的意思是,每个雇员都有年薪或计时工资,但不能都有。因此,在创建TEmployee时,没有理由为两个字段都分配足够的内存。这种情况下,变体之间只有名字不同,而要想让字段的类型不同也是很容易的。考虑相对复杂的例子:
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;
对上面的每个记录实例,编译器分配足够的内存以在最大的变体中能够保存所有的字段。可选的Tag和常量列表constantLists(如上面最后一个例子中Rectangle、Triangle等)在编译器管理字段的途径中不扮演任何角色,它们仅为程序员提供方便。
变体部分的第二个用途是,可以将相同的数据视为不同的类型,尤其在编译器不允许类型转换的情况。例如,如果有一个64位的实数Real类型作为变体的第一个字段,一个32位的整数Integer类型作为另一个变体的第一个字段,那么可以向实数Real字段赋值然后以整数Integer字段读出其前32位(简单地说,作用就是请求整数参量)。