繁体   English   中英

Delphi内存拷贝与记录到另一个记录

[英]Delphi Memory copy with Record to another Record

我遇到逻辑问题。 我不知道如何将记录复制到Delphi中的另一条记录。

TypeA = record
  value1 : word;
  value2 : word;
  value3 : word;
  end;

TypeB = record
  b1 : byte;
  b2 : byte;    
  end;

我有两个记录TypeA和TypeB。 例如,我发现TypeA记录中的数据属于TypeB记录。 注意:TypeA具有更长的数据长度。

问题:如何复制TypeA内存并将其放在TypeB记录中?

CopyMemory(@TypeA, @TypeB, Length(TypeB))

当我尝试CopyMemory并得到一个错误(无法比较的类型)

PS:我不想像下面那样复制或分配它。

TypeB.b1:= TypeA.value1 && $ FF;

TypeA和TypeB只是示例记录。 大多数情况下,记录TypeA和TypeB可能包含多个记录,并且分配表单TypeA并分配给TypeB记录将更加困难。

提前致谢

----加法问题:

有没有办法将Delphi记录复制到Byte数组以及如何? 如果有,

  • TypeA记录到字节数组
  • 字节数组到B类

这个逻辑会起作用吗?

CopyMemory(@a, @b, SizeOf(TypeB))

如果aTypeA类型而bTypeB类型。

变体记录:

TypeA = packed record
  value1 : word;
  value2 : word;
  value3 : word;
  end;

TypeB = packed record
  b1 : byte;
  b2 : byte;
  end;

TypeAB = packed record
  case boolean of
    false:(a:TypeA);
    true:(b:TypeB);
end;
..
..
var someRec:TypeAB;
    anotherRec:TypeAB;
..
..
  anotherRec.b:=someRec.b
procedure CopyAtoB( const A: TypeA; var B: TypeB);
begin
// Assume A is bigger than B.
Move( A, B, SizeOf( TypeB))
end;

或(用数学单位)

procedure CopyAtoB( const A: TypeA; var B: TypeB);
begin
// No assumptions about A, B sizes.
FillChar( B, SizeOf( B), 0);
Move( A, B, Min( SizeOf( TypeA), SizeOf( TypeB)))
end;

将A记录复制到B记录有一个很好的方法 - 运算符重载; 在这种情况下,您可以简单地重载Implicit和Explicit操作并编写代码,如b := a

program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses System.SysUtils;

type
    TTypeA = record
      value1 : integer;
      value2 : integer;
      value3 : integer;
    end;

    TTypeB = record
      b1 : byte;
      b2 : byte;
      class operator Implicit(value : TTypeA):TTypeB;
    end;

class operator TTypeB.Implicit(value: TTypeA): TTypeB;
begin
    result.b1 := Hi(value.value1);
    result.b2 := Lo(value.value1);
end;


var a : TTypeA;
    b : TTypeB;
begin
    b := a;
end.

您可以使用TBytesStream将记录复制到字节数组:

var a : TTypeA;
    bs : TBytesStream;
    bArr : TArray<byte>;//array of byte;
begin
    bs := TBytesStream.Create();
    bs.Write(a, sizeof(a));
    bArr := bs.Bytes;
end;

或者只是将字节数组的大小设置为sizeof(A)然后再设置copyMemory

所有其他答案都是直接复制内存的变体,但我认为这是错误的方法。 它是低级的,您使用的是高级语言,很容易出错,如果您的记录包含托管数据类型,则存在风险。

如果你想要获取记录的一个元素的前两个字节,请尝试使用变体记录 (在C中,一个联合。)它是一个记录的一部分,可以通过多种方式解决,在这里你想要将其作为一个字或一系列字节来处理。

尝试这样的事情(未经测试,只需在SO编辑器中输入):

type
  TTwoBytes : packed record
    ByteA, ByteB : Byte;
  end;

  TValueRecord : packed record:
    case Boolean of
      True: (Value: SmallInt);
      False: (ValueBytes : TTwoBytes);
    end;
  end;

  TMyRecord = packed record
    Value1, Value2, Value3 : TValueRecord;
  end;

然后代码:

var
  MyRecord: TMyRecord;
  MyBytes: TTwoBytes;
begin
  MyRecord := ...; // Fill it with data here
  // Access the words / smallints by something like: MyRecord.Value1.Value
  MyBytes := MyRecord.ValueBytes; // The key bit: type safe assignment
  // Do something with MyBytes.ByteA or MyBytes.ByteB
end;

这给你带来什么比直接复制内存更好?

  • 这是安全的:如果你有更复杂的记录包含字符串,接口等,它仍然可以工作而不会破坏引用计数。
  • 它是类型安全的:没有直接复制内存:你和编译器都知道你拥有和正在使用的内容。
  • 这是规范的:这可能是“德尔福方式”。 (虽然有几种方法可以构建记录 - 如果你看一下答案历史,我原来的情况就更糟了。另外我觉得'这个' case ... of '语法'是愚蠢的,但这是另一个讨论......: ))

一些说明:

您可以通过以下方式省略CopyMemory()(Windows单位)使用:

type
  PTypeA = ^TTypeA;
  TTypeA = record
    value1 : word;
    value2 : word;
    value3 : word;
  end;
  PTypeB = ^TTypeB;
  TTypeB = record
    b1 : byte;
    b2 : byte;
  end;
var
  A: TTypeA = (value1 : 11; value2 : 22; value3 : 33);
  B: TTypeB;
  B1: TTypeB;
  C: {packed?} array of Byte;
begin
  Assert(SizeOf(TTypeA) >= SizeOf(TTypeB));
  //...
  B:= PTypeB(@A)^;
  //...
  SetLength(C, SizeOf(A));
  // TTypeA record to Byte Array
  PTypeA(@C[0])^:= A;
  // Byte Array to TTypeB
  B1:= PTypeB(@C[0])^
end;

如果您只想将字节从一个地方复制到另一个地方,请使用MOVE而不是CopyMemory。

要获得记录的大小,请使用SizeOf而不是Length。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM