Delphi 内存复制与记录到另一个记录

发布于 2025-01-08 15:55:05 字数 856 浏览 0 评论 0原文

我的逻辑有问题。我不知道如何在 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记录复制到字节数组,如何?如果有,

  • TypeA 记录到 Byte Array
  • Byte Array 到 Type B

这个逻辑行得通吗?

I am having problem with the logic. I have no idea how to copy record to another record in 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. For example, I found out that data in TypeA record is belong to TypeB records. Note: TypeA has longer Data Length.

Question: How do i copy TypeA memory and place it in TypeB record?

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

When i tried CopyMemory and got an error (Incompaible types).

PS: I don't want to copy or assign it like below.

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

TypeA and TypeB are just example records. 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.

Thanks in advance

----Addition question:

Is there a way to copy Delphi record to Byte array and how? If there is,

  • TypeA record to Byte Array
  • Byte Array to Type B

Will this logic work?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

岁月静好 2025-01-15 15:55:05
CopyMemory(@a, @b, SizeOf(TypeB))

如果 a 的类型为 TypeA,而 b 的类型为 TypeB

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

if a is of type TypeA and b is of type TypeB.

乖乖兔^ω^ 2025-01-15 15:55:05

变体记录:

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

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
负佳期 2025-01-15 15:55:05
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;
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;
饮湿 2025-01-15 15:55:05

将A记录复制到B记录有一个好方法——运算符重载;在这种情况下,您可以简单地重载隐式和显式操作并编写类似 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),然后复制内存

to copy A record to B record there is a good way - operator overloading; in this case you can simply overload Implicit and Explicit operations and write code likeb := 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:

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

追星践月 2025-01-15 15:55:05

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

如果您尝试获取记录的一个元素的前两个字节,请尝试使用变体记录(在 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' 语法很愚蠢,但是这是另一个讨论...:))

一些注意事项:

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.

Try something like this (untested, just typed in the SO editor):

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... :))

Some notes:

人间不值得 2025-01-15 15:55:05

您可以通过以下方式省略 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;

You can omit CopyMemory() (Windows unit) use by:

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;
红颜悴 2025-01-15 15:55:05

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

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

Use MOVE instead of CopyMemory if you want to simply copy the bytes from one place to another.

And to get the size of a record use SizeOf instead of Length.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文