Copy Delphi memory to another record

I have a problem with logic. I do not know how to copy a record to another record in Delphi.

TypeA = record value1 : word; value2 : word; value3 : word; end; TypeB = record b1 : byte; b2 : byte; end; 

I have two TypeA and TypeB entries. For example, I found out that the data in the TypeA record refers to typeB records. Note. Type A has a longer data length.

Question: How do I copy TypeA memory and put it in a TypeB record?

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

When I tried CopyMemory and got an error (incompatible types).

PS: I do not want to copy or assign it as shown below.

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

TypeA and TypeB are only examples of records. In most cases, TypeA and TypeB records can contain multitasking records, and it will be more difficult to select the TypeA form and assign the type B records.

Thanks in advance

---- Additional question:

Is there a way to copy a Delphi entry into an byte array and how? If there's,

  • Writing TypeA to a byte array
  • Byte array for type B

Will this logic work?

+4
source share
7 answers
 CopyMemory(@a, @b, SizeOf(TypeB)) 

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

+7
source

Record Options:

 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 
+4
source
 procedure CopyAtoB( const A: TypeA; var B: TypeB); begin // Assume A is bigger than B. Move( A, B, SizeOf( TypeB)) end; 

or (using the Math module)

 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
source

to copy an entry to entry B, there is a good way - operator overloading; in this case, you can simply overload the implicit and explicit operations and write code like 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 a record to an array of bytes:

 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 just set the size of the byte array to sizeof(A) and then copyMemory

+3
source

All other answers are options for copying memory directly, but I think this is the wrong approach. . This is a low-level language, and you use a high-level language, it's easy to make mistakes, and it's risky if your records contain manageable data types.

If you are trying to get the first two bytes of a single record element, try using a variant record (in C, concatenation). This is part of a record that can be solved in several ways, and here you want to access it either as a word or a series of bytes.

Try something like this (unverified, just typed in 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 the 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 better than directly copying memory?

  • This is safe: if you have more complex entries containing strings, interfaces, etc., it will still work without breaking the number of links.
  • Safe type: no direct memory copy: you and the compiler know what you have and use.
  • This is canonical: this is probably the โ€œDelphi wayโ€ to do this. (Although there are several ways to structure records - if you look in the history of answers, it was worse from the beginning. I also think that the syntax " case ... of " is silly for this, but this is another discussion ... :))

Some notes:

+3
source

You can omit CopyMemory () (Windows block) using:

 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; 
+2
source

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

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

0
source

Source: https://habr.com/ru/post/1397944/


All Articles