简体   繁体   English

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

[英]Delphi Memory copy with Record to another Record

I am having problem with the logic. 我遇到逻辑问题。 I have no idea how to copy record to another record in Delphi. 我不知道如何将记录复制到Delphi中的另一条记录。

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

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

I have my two records TypeA and TypeB. 我有两个记录TypeA和TypeB。 For example, I found out that data in TypeA record is belong to TypeB records. 例如,我发现TypeA记录中的数据属于TypeB记录。 Note: TypeA has longer Data Length. 注意:TypeA具有更长的数据长度。

Question: How do i copy TypeA memory and place it in TypeB record? 问题:如何复制TypeA内存并将其放在TypeB记录中?

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

When i tried CopyMemory and got an error (Incompaible types) . 当我尝试CopyMemory并得到一个错误(无法比较的类型)

PS: I don't want to copy or assign it like below. PS:我不想像下面那样复制或分配它。

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

TypeA and TypeB are just example records. TypeA和TypeB只是示例记录。 Most of thecases, record TypeA and TypeB may contain multple records and it will be harder to allocate form TypeA and assign to TypeB record. 大多数情况下,记录TypeA和TypeB可能包含多个记录,并且分配表单TypeA并分配给TypeB记录将更加困难。

Thanks in advance 提前致谢

----Addition question: ----加法问题:

Is there a way to copy Delphi record to Byte array and how? 有没有办法将Delphi记录复制到Byte数组以及如何? If there is, 如果有,

  • TypeA record to Byte Array TypeA记录到字节数组
  • Byte Array to Type B 字节数组到B类

Will this logic work? 这个逻辑会起作用吗?

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

如果aTypeA类型而bTypeB类型。

Variant records: 变体记录:

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;

or (with Math unit) 或(用数学单位)

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;

to copy A record to B record there is a good way - operator overloading; 将A记录复制到B记录有一个很好的方法 - 运算符重载; in this case you can simply overload Implicit and Explicit operations and write code like b := a : 在这种情况下,您可以简单地重载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.

you can use TBytesStream to copy record to byte array: 您可以使用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;

or simply set size of byte array to sizeof(A) and then copyMemory 或者只是将字节数组的大小设置为sizeof(A)然后再设置copyMemory

All the other answers are variations of copying memory directly, but I think that is the wrong approach. 所有其他答案都是直接复制内存的变体,但我认为这是错误的方法。 It's low-level and you're using a high-level language, it's easy to make mistakes, and it is risky if your records contain managed data types. 它是低级的,您使用的是高级语言,很容易出错,如果您的记录包含托管数据类型,则存在风险。

If you're trying to get the first two bytes of one element of a record, try using a variant record (in C, a union.) It is a section of a record that can be addressed several ways, and here you want to address it either as a word or series of bytes. 如果你想要获取记录的一个元素的前两个字节,请尝试使用变体记录 (在C中,一个联合。)它是一个记录的一部分,可以通过多种方式解决,在这里你想要将其作为一个字或一系列字节来处理。

Try something like this (untested, just typed in the SO editor): 尝试这样的事情(未经测试,只需在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;

Then for code: 然后代码:

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;

What does this give you that's better than directly copying memory? 这给你带来什么比直接复制内存更好?

  • It's safe: if you have more complicated records containing strings, interfaces etc, it will still work without breaking reference counts. 这是安全的:如果你有更复杂的记录包含字符串,接口等,它仍然可以工作而不会破坏引用计数。
  • It's type safe: no direct copying of memory: you and the compiler both know what you have and are using. 它是类型安全的:没有直接复制内存:你和编译器都知道你拥有和正在使用的内容。
  • It's canonical: this is probably 'the Delphi way' to do it. 这是规范的:这可能是“德尔福方式”。 (Although there are several ways to structure the records - if you look in the answer history I had a worse one originally. Also I think the ' case ... of ' syntax for this is silly, but that's another discussion... :)) (虽然有几种方法可以构建记录 - 如果你看一下答案历史,我原来的情况就更糟了。另外我觉得'这个' case ... of '语法'是愚蠢的,但这是另一个讨论......: ))

Some notes: 一些说明:

You can omit CopyMemory() (Windows unit) use by: 您可以通过以下方式省略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;

Use MOVE instead of CopyMemory if you want to simply copy the bytes from one place to another. 如果您只想将字节从一个地方复制到另一个地方,请使用MOVE而不是CopyMemory。

And to get the size of a record use SizeOf instead of Length. 要获得记录的大小,请使用SizeOf而不是Length。

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

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