在ATTI中TTypeKind下
TTypeKind = (tkUnknown, tkInteger, tkChar, tkEnumeration, tkFloat,tkString, tkSet, tkClass, tkMethod, tkWChar, tkLString, tkWString,tkVariant, tkArray, tkRecord, tkInterface, tkInt64, tkDynArray, tkUString,tkClassRef, tkPointer, tkProcedure);
在他们的代码里面有个地方很不解,procedure       _InitializeArray(p: Pointer; typeInfo: Pointer; elemCount: Cardinal);
var    FT: PFieldTable;
begin
  if elemCount = 0 then Exit;
  case PTypeInfo(typeInfo).Kind of
    tkLString, tkWString, tkInterface, tkDynArray, tkUString:
      while elemCount > 0 do
      begin
        PInteger(P)^ := 0;
        Inc(Integer(P), 4);
        Dec(elemCount);
      end;    tkVariant:
      while elemCount > 0 do
      begin
        PInteger(P)^ := 0;
        PInteger(Integer(P)+4)^ := 0;
        PInteger(Integer(P)+8)^ := 0;
        PInteger(Integer(P)+12)^ := 0;
        Inc(Integer(P), sizeof(Variant));
        Dec(elemCount);
      end;    tkArray:
      begin
        FT := PFieldTable(Integer(typeInfo) +  ));
        while elemCount > 0 do
        begin
          _InitializeArray(P, FT.Fields[0].TypeInfo^, FT.Count);
          Inc(Integer(P), FT.Size);
          Dec(elemCount);
        end;
      end;    tkRecord:
      begin
        FT := PFieldTable(Integer(typeInfo) + Byte(PTypeInfo(typeInfo).Name[0]));
        while elemCount > 0 do
        begin
          _InitializeRecord(P, typeInfo);
          Inc(Integer(P), FT.Size);
          Dec(elemCount);
        end;
      end;
  else
    Error(reInvalidPtr);
  end;
end;
 FT := PFieldTable(Integer(typeInfo) + Byte(PTypeInfo(typeInfo).Name[0])); 
为什么还要加上Byte(PTypeInfo(typeInfo).Name[0])) ?前面已经得到TypeInfo的地址了呀?

解决方案 »

  1.   

    对于Record等类型, 只取得typeInfo是不够的, 因为它有可能有多个字段,所以要取得它的字段表指针PFieldTable,然后再根据每个字段的类型初始化,而PFieldTable仅仅是typeInfo存储空间的一部分,
    在typeInfo偏移Byte(PTypeInfo(typeInfo).Name[0]) 处.  
      

  2.   


    在system.pas 里面 对于TFieldTable定义如下Type
      PPTypeInfo = ^PTypeInfo;
      PTypeInfo = ^TTypeInfo;
      TTypeInfo = packed record
        Kind: Byte;
        Name: ShortString;
       {TypeData: TTypeData}
      end;  TFieldInfo = packed record
        TypeInfo: PPTypeInfo;
        Offset: Cardinal;
      end;  PFieldTable = ^TFieldTable;
      TFieldTable = packed record
        X: Word;
        Size: Cardinal;
        Count: Cardinal;
        Fields: array [0..0] of TFieldInfo;
      end;而过程_InitializeRecord实现如下:
    procedure   _InitializeRecord(p: Pointer; typeInfo: Pointer);
    {$IFDEF PUREPASCAL}
    var
      FT: PFieldTable;
      I: Cardinal;
    begin
      FT := PFieldTable(Integer(typeInfo) + Byte(PTypeInfo(typeInfo).Name[0]));
      for I := FT.Count-1 downto 0 do
        _InitializeArray(Pointer(Cardinal(P) + FT.Fields[I].Offset), FT.Fields[I].TypeInfo^, 1);
    end;TypInfo中TTypeInfo,RecordTypeField和TArrayTypeData 定义如下:  PPTypeInfo = ^PTypeInfo;
      PTypeInfo = ^TTypeInfo;
      TTypeInfo = record
        Kind: TTypeKind;
        Name: ShortString;
       {TypeData: TTypeData}
      end;  PArrayTypeData = ^TArrayTypeData;
      TArrayTypeData = packed record
        Size: Integer;
        ElCount: Integer; // product of lengths of all dimensions
        ElType: PPTypeInfo;
        DimCount: Byte;
        Dims: array[0..255 {DimCount-1}] of PPTypeInfo;
      end;  PManagedField = ^TManagedField;
      TManagedField = packed record
        TypeRef: PPTypeInfo;
        FldOffset: Integer;
      end;  PRecordTypeField = ^TRecordTypeField;
      TRecordTypeField = packed record
        Field: TManagedField;
        Flags: Byte;
        Name: ShortString;
       {AttrData: TAttrData;}
      end;对于一个Record的类型相关信息其内存排布如下:
    首先4个字节的PtypeInfo,   指向紧接着下来的地方,既是TTypeInfo。
    TTypeInfo包括 一个字节的TTypeKind和一个字符串,总字节数(1+1+n),1个字节是TypeKind,一个字节存储n(n为字符串长度)接着n个字符。
    接下来是上面定义的TRecordTypeField;对于一个array的类型相关信息其内存排布如下:
    首先4个字节的PtypeInfo,   指向紧接着下来的地方,既是TTypeInfo。
    TTypeInfo包括 一个字节的TTypeKind和一个字符串,总字节数(1+1+n),1个字节是TypeKind,一个字节存储n(n为字符串长度)接着n个字符。
    接下来是上面定义的TArrayTypeData;我的问题是:
    其一,难道TFieldTable和RTTI的数据是兼容的?不然无法解释二者都读取同一块内存。
    其二,退一步说,即便兼容。typeInfo既然已经是该类型RTTI信息的起始地址, FT := PFieldTable(Integer(typeInfo) + Byte(PTypeInfo(typeInfo).Name[0]))也没能跳过TTypekind的边界。怎么可能获取正确的信息呢?FT的指向也是错误的。