Delphi XE3 -> Integer to array of Bytes
Asked Answered
M

6

6

I have a data structure:

data = array of integer;

I have filled it from an

source = array of byte;

with

data[x] := Source[offset] or (Source[offset + 1] shl 8) or
    (Source[offset + 2] shl 16) or (Source[offset + 3] shl 24);

after processing these blocks i have to bring them back to "bytes"...

any idea?

Mono answered 29/11, 2012 at 20:32 Comment(3)
Why don't you just blit them with Move? And if there's a network/host byte order change, then do that separately with ntohl.Insinuation
I agree with @David, although it is possible to give a direct answer to your question, I get the feeling that you could rethink your design.Frilling
i did it that way cause it was just a quick "port" from c++ to delphi. in c++ the first "transformation" was just int data = (int)source where the source was declared as unsigned char *sourceMono
I
8

You can do this in a one-liner using Move.

Move(source[0], dest[0], Length(source)*SizeOf(source[0]));

If you need to perform a network/host byte order transformation, then you can run across the integer array after the Move.

In the opposite direction you do it all in reverse.

If you haven't got byte order issues then you might not actually need to convert to a byte array at all. It's possible that you can use the integer array as is. Remember that, without byte order issues, the memory layout of the byte and integer arrays are the same (which is why you are able to blit with Move).

Insinuation answered 29/11, 2012 at 20:46 Comment(2)
Indeed. But I get the feeling that the data probably can be used for anything in any form, so I suspect that the OP need not copy anything at all...Frilling
@Andreas Funny timing. I came to same conclusion and wrote it up, and then saw your comment!Insinuation
F
9

You mean like this?

var
  i: integer;
  b1, b2, b3, b4: byte;
begin
  b1 := byte(i);
  b2 := byte(i shr 8);
  b3 := byte(i shr 16);
  b4 := byte(i shr 24);

Try, for instance,

procedure TForm1.FormCreate(Sender: TObject);
var
  i: integer;
  b1, b2, b3, b4: byte;
begin
  i := $AABBCCDD;
  b1 := byte(i);
  b2 := byte(i shr 8);
  b3 := byte(i shr 16);
  b4 := byte(i shr 24);
  ShowMessage(IntToHex(b1, 2));
  ShowMessage(IntToHex(b2, 2));
  ShowMessage(IntToHex(b3, 2));
  ShowMessage(IntToHex(b4, 2));
end;
Frilling answered 29/11, 2012 at 20:34 Comment(2)
Thank you. I believe I have not seen the forest for the trees.Mono
@Michael This answer is trees. Forest is still out there waiting for you to find it! And I mean no offence to Andreas who said as much in a comment above.Insinuation
I
8

You can do this in a one-liner using Move.

Move(source[0], dest[0], Length(source)*SizeOf(source[0]));

If you need to perform a network/host byte order transformation, then you can run across the integer array after the Move.

In the opposite direction you do it all in reverse.

If you haven't got byte order issues then you might not actually need to convert to a byte array at all. It's possible that you can use the integer array as is. Remember that, without byte order issues, the memory layout of the byte and integer arrays are the same (which is why you are able to blit with Move).

Insinuation answered 29/11, 2012 at 20:46 Comment(2)
Indeed. But I get the feeling that the data probably can be used for anything in any form, so I suspect that the OP need not copy anything at all...Frilling
@Andreas Funny timing. I came to same conclusion and wrote it up, and then saw your comment!Insinuation
E
7

Hmmm... I see an answer using Move and one using shifts, but what about a simple cast?:

var
  I: Integer;
  B: array[0..3] of Byte;
begin
  // from bytes to integer:
  I := PInteger(@B)^;
  // from integer to bytes:
  PInteger(@B)^ := I;

Or with your arrays:

data[i] := PInteger(@source[offset])^;

and vice versa:

// get low byte
source[offset] := PByte(@data[i])^; // or := PByte(@data[i])[0];
// get second byte
secondByte := PByte(@data[i])[1]; // or := (PByte(@data[i]) + 1)^;

or

PInteger(@source[offset])^ := data[i];

As you see, you can get a long way by casting to pointers. This does not actually take the pointer, the compiler is clever enough to access the items directly.

Enlightenment answered 29/11, 2012 at 21:8 Comment(3)
Dare I mention absolute? That would eliminate the need for assignments (those that move the entire contents one way or the other) altogether.Sedlik
You shouldn't dare ;-) IMO, absolute is an abomination and should be removed from the language. But if you want to discuss why, use the Embarcadero forums.Enlightenment
FWIW, if you don't need to assign, you don't. In this case there was a need. If there is no need, you can easily use the same casts. I used assignment to demonstrate that the result is really a byte or an integer, depending on your needs.Enlightenment
G
0

As commented, you do not need to move the data to access it as both byte and integer.

Your original array of byte could be accessed as an array of integer by type casting.

type
  TArrayInteger = array of Integer;
...
for i := 0 to Pred(Length(source)) div SizeOf(Integer) do
  WriteLn(TArrayInteger(source)[i]);

Often I hide these type casts in a class. In XE3 there is possibility to declare class helpers for simple types, like string,byte,integers, etc. See TStringHelper for example. The same goes for array of simple types.

Here is an example using a record helper:

type
  TArrayByte = array of Byte;
  TArrayInteger = array of Integer;

  TArrayByteHelper = record helper for TArrayByte
  private
    function GetInteger(index : Integer) : Integer;
    procedure SetInteger(index : Integer; value : Integer);
  public
    property AsInteger[index : Integer] : Integer read GetInteger write SetInteger;
  end;

function TArrayByteHelper.GetInteger(index: Integer): Integer;
begin
  Result := TArrayInteger(Self)[index];
end;

procedure TArrayByteHelper.SetInteger(index: Integer; value: Integer);
begin
  TArrayInteger(Self)[index] := value;
end;

Use it like this:

Var
  source : TArrayByte;
  i : Integer;
begin
  SetLength(source,8);
  for i := 0 to 7 do
    source[i] := i;
  for i := 0 to 1 do
    WriteLn(Format('%8.8X',[source.AsInteger[i]]));
  ReadLn;
end.
Galla answered 29/11, 2012 at 22:15 Comment(0)
C
0

To build this as a function:

Type TBytes = array of byte;

function InttoBytes(const int: Integer): TBytes;
begin
  result[0]:= int and $FF;
  result[1]:= (int shr 8) and $FF;
  result[2]:= (int shr 16) and $FF;
end;
Cribb answered 2/12, 2020 at 8:50 Comment(0)
A
0

it is not possible to correctly convert Integer to Byte array [4] since Integer has plus and minus, this option simply allows you to directly access Byte in Integer as an array, without any tricks...

var
  I: Integer;
  B: array[0..3] of Byte absolute I;
Arteaga answered 23/8, 2024 at 2:6 Comment(1)
What is this contributing beyond what has already been suggested? Explaining your code is encouraged on StackOverflow, but that’s especially important here, on an old question with several answers validated by members of the community.Procter

© 2022 - 2025 — McMap. All rights reserved.