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语句中间应该是一个有序的变量吗?怎么会是两个类型?
不能理解,还请大侠高手指点,谢谢!

解决方案 »

  1.   

    这个相当于C里面的Union结构,也就是共用体.你可以在Delphi帮助下查找variant parts in records,有详细说明.
      

  2.   

    在Delphi中这个叫变体记录:
    type
      TVarRec=record
         case Byte of
              vtInteger: (VInteger:Integer;VType:Byte);
              vtBoolean: (VBoolean:Boolean);
            ...
        end;表示TVarRec记录即可以看作是VInteger:Integer;VType:Byte, 也可以看作为VBoolean:Boolean的存放,但两者只能选一。Byte只是一个无名标识,并没有太大的意义。
    里面的vtInteger 肯定是一常量
      

  3.   

    还是不太理解,例如在下面inaddr这个记录类型中,为什么s3不可以直接定义为string?我将s3定义string时,系统就报错。并且在显示a.s1,a.s2时,都是显示一个很大的数,1667391748,这个数是怎么得来的?但b.s1,b.s2就是显示1,2
    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;
      

  4.   

    给你讲一点 你可能就知道了这种类似union的结构体中所占用的内存是里面最大的哪个数据结构所占用的内存,因为可以共用,也可以被最大的用
    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了。。
      

  5.   

    beyondtkl大侠,再向您请教一下,
    case integer of
          0: (s1: Integer);
          1: (s2: Integer);
          2: (s3: String[10]); // 必须是
    end;
    上面case语句中,请问0,1,2是否只是起到一个序号的作用?在调用时,和普通的结构体是一样的调用,只是内存分配不同。
    是这样吗?
      

  6.   

    case integer of
          0: (s1: Integer);
          1: (s2: Integer);
          2: (s3: String[10]); // 必须是
    end;
    上面case语句中,请问0,1,2是否只是起到一个序号的作用?
    0, 1, 2表示三种情况,就是说这个结构体允许三种数据结构共存 就像一个瓶子里面,可是同时放三样东西 当然他们只占一个瓶子的空间  不过一般来说 有意义的数据只有一个<这要看自己去分析>在调用时,和普通的结构体是一样的调用,只是内存分配不同。
    是这样吗?
    分配内存 值得系统的分配不一样而已,,调用 你上面都已经调用了
      

  7.   

    type
       TPerson = record
          case Citizen: Boolean of
             True: (Birthplace: string[10]);
             False: (Country: string[5]);
          end;像上面case语句中citizen这个变量有何作用呢?
    是不是只是起到一个标识作用?让程序员可以知道这个变体部分内容的含义?
    大侠,还请您指点,谢谢!
      

  8.   

    是不是只是起到一个标识作用?让程序员可以知道这个变体部分内容的含义?这个true,false就是像你说的 标识 作用像上面case语句中citizen这个变量有何作用呢?
    这个变量有没有都可以case Boolean of // 也可以的
      

  9.   

    记录类型问题! 
    主要解答者: 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位(简单地说,作用就是请求整数参量)。