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

时间:2012-02-23 03:35:43

标签: delphi memory copy 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

这种逻辑会起作用吗?

7 个答案:

答案 0 :(得分:7)

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

如果a的类型为TypeAb的类型为TypeB

答案 1 :(得分:5)

变体记录:

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

答案 2 :(得分:3)

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;

答案 3 :(得分:3)

将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

答案 4 :(得分:3)

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

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

有些说明:

答案 5 :(得分:2)

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

答案 6 :(得分:0)

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

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