无效类型转换:在 64 位平台上将记录转换为 tobject

问题描述 投票:0回答:4

它适用于 32 位平台,但不适用于 64 位平台 这是例子

  TVerbInfo = packed record
    Verb: Smallint;
    Flags: Word;
  end;

var
  VerbInfo: TVerbInfo;
  strList : TStringList;
  verb : Smallint;
  flags : Word;
begin
  strList := TStringList.create();
  .....
  verbInfo.verb := verb;
  verbInfo.flags := flags;
  strList.addObject('verb1',TObject(VerbInfo));  //invalid typecast happened here
end;

有人可以帮助我吗?非常感谢你

delphi casting 64-bit record tobject
4个回答
4
投票

你可以尝试这样的事情:

function MakeVerbInfoObject(const AVerbInfo: TVerbInfo): TObject;
begin
  Result := nil;
  Move(AVerbInfo, Result, SizeOf(AVerbInfo));
end;

strList.addObject('verb1', MakeVerbInfoObject(VerbInfo));

3
投票

您的演员表

TObject(VerbInfo)
将编译,前提是
SizeOf(TObject) = SizeOf(TVerbInfo)
。但
TObject
是一个指针,因此它的大小因架构而异。另一方面,
SizeOf(TVerbInfo)
不随架构而变化。因此,演员只能在一种架构上工作。

使用像这样的强制转换就是在前泛型 Delphi 中必须做的事情。但现在,您应该使用通用容器。

例如,如果您有一个列表并且字符串是唯一的,那么您可以使用字典:

TDictionary<string, TVerbInfo>

如果可能存在重复的字符串,那么您将需要一个新的记录声明:

type
  TVerbInfo = record
    Name: string
    Verb: Integer;
    Flags: Word;
  end;

然后将这些列表存储在

TList<TVerbInfo>

最后一点是您应该避免使用打包记录。这些会导致数据结构不对齐,进而导致性能不佳。


1
投票

我认为你必须在不同的平台上运行它并比较结果

ShowMessage( IntToStr( SizeOf( Integer ) ) );
ShowMessage( IntToStr( SizeOf( Pointer ) ) );
ShowMessage( IntToStr( SizeOf( TVerbInfo ) ) );
ShowMessage( IntToStr( SizeOf( TObject ) ) );

我怀疑你不能进行硬铸,因为尺寸不同。

您可以尝试使用类似的解决方法

type TBoth = record
  case byte of
    0: ( rec: TVerbInfo);
    1: ( obj: TObject);
  end;

您也可以尝试使用

TDictionary<String, TVerbInfo>
类型代替
TStringList


0
投票

我昨晚尝试了 Uli 的代码,但它不起作用,因为 MakeVerbInfoObject 不会为您提供指向记录的有效指针。

type
  PVerbInfo= ^TVerbInfo;
  TVerbInfo = packed record
    Verb: Smallint;
    Flags: Word;
  end;


function MakeVerbInfoObject(const AVerbInfo: TVerbInfo): TObject;
begin
  Result := nil;
  Move(AVerbInfo, Result, SizeOf(AVerbInfo));
end;


procedure Test;
var
   VerbInfo: TVerbInfo;
   List: TObjectList;
begin
  VerbInfo.Verb:= 7;
  VerbInfo.Flags:= 8;

  List:= TObjectList.Create(false);
  List.Add(MakeVerbInfoObject(VerbInfo));

  // AV here!!!!!!!!
  var i:= PVerbInfo(List[0])^.Verb;

  FreeAndNil(List);
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  Test2;
end;

但是,这可以工作(在 32/64 位上测试):

Type
 PVerbInfo2= ^TVerbInfo2;
 TVerbInfo2= packed record
   Verb: SmallInt;
   Flags: Word;
 end;


procedure Test;
var
   VerbInfo: TVerbInfo2;
   Obj: TObject;
   List: TObjectList;
   P: PVerbInfo2;
begin
  VerbInfo.Flags:= 7;
  VerbInfo.Verb:= 8;

  List:= TObjectList.Create(false);

  //List.add(Pointer(VerbInfo));    // "E2089 Invalid typecast" when compiling on 64 bit

  List.Add(TObject(@VerbInfo));

  // This gives correct values:
  var i := PVerbInfo2(List[0])^.Verb;

  FreeAndNil(List);
end;
© www.soinside.com 2019 - 2024. All rights reserved.