簡體   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