在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的地址了呀?
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的地址了呀?
在typeInfo偏移Byte(PTypeInfo(typeInfo).Name[0]) 处.
在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的指向也是错误的。