Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Bytes auf ein Integer auffädeln (https://www.delphipraxis.net/197815-bytes-auf-ein-integer-auffaedeln.html)

Kostas 6. Sep 2018 21:33

Bytes auf ein Integer auffädeln
 
Hallo Zusammen,

um z.B.: zwei Bytes auf ein Integer aufzufädeln mache ich das so:

Delphi-Quellcode:
var L: Integer;
begin
  L := FReceiveBuffer[9];
  L := L shl 8;
  L := L or FReceiveBuffer[10];
end;
Ich setze gerade ein Protokoll um und da muss ich diese Aktion öfters machen von ein bis vier Bytes auf ein Integer auffädeln.
Gibt es eine elegantere Möglichkeit dafür?

Gruß Kostas

Zacherl 6. Sep 2018 21:42

AW: Bytes auf ein Integer auffädeln
 
Zitat:

Zitat von Kostas (Beitrag 1412643)
Gibt es eine elegantere Möglichkeit dafür?

Definitiv! Sofern die Byte-Order garantiert gleich ist, kannst du auch einfach direkt den Datentyp auslesen, den du brauchst (z.B. Int16, Int32, ..) bzw. den Buffer dahingehend casten mit
Delphi-Quellcode:
L := PInt16(@FReceiveBuffer[9])^
. Eventuell macht es ja sogar Sinn für jedes Paket ein
Delphi-Quellcode:
struct
zu deklarieren (vorrausgesetzt die Struktur ist immer gleich groß) und dann direkt in einem Rutsch auszulesen.

Delphi.Narium 6. Sep 2018 22:06

AW: Bytes auf ein Integer auffädeln
 
Keine Ahnung, ginge sowas?
Delphi-Quellcode:
type
  t4 = record
    a : Byte;
    b : byte;
    c : Byte;
    d : Byte;
  end;

var
  i : Integer;
  r4 : t4 absolute i;
begin
  r4.a := FReceiveBuffer[0];
  r4.b := FReceiveBuffer[1];
  r4.c := FReceiveBuffer[2];
  r4.d := FReceiveBuffer[3];
end;
Da r4 an der gleichen Adresse liegt wie i, müsste i nun die 4 Bytes enthalten.
Ob's hier jetzt schon die von Dir gewünschte Reichenfolge ist, weiß ich nicht.
Aber das ließe sich ja ggfls. einfach durch Änderungen der Reihenfolge bei der Zuweisung ändern.

Kostas 6. Sep 2018 22:11

AW: Bytes auf ein Integer auffädeln
 
Zitat:

Zitat von Zacherl (Beitrag 1412644)
Zitat:

Zitat von Kostas (Beitrag 1412643)
Gibt es eine elegantere Möglichkeit dafür?

Definitiv! Sofern die Byte-Order garantiert gleich ist, kannst du auch einfach direkt den Datentyp auslesen, den du brauchst (z.B. Int16, Int32, ..) bzw. den Buffer dahingehend casten mit
Delphi-Quellcode:
L := PInt16(@FReceiveBuffer[9])^
. Eventuell macht es ja sogar Sinn für jedes Paket ein
Delphi-Quellcode:
struct
zu deklarieren (vorrausgesetzt die Struktur ist immer gleich groß) und dann direkt in einem Rutsch auszulesen.

sorry das ich nachfrage, aber wie bekomme ich das zweite Byte auf den Integer aufgefädelt? Ich habe eigentlich nur vier Varianten Auf dem Integer L werden 1,2,3 oder 4 Bytes aufgefädelt.
Gruß Kostas

himitsu 6. Sep 2018 22:27

AW: Bytes auf ein Integer auffädeln
 
Es gibt auch fertige Funktionen ala Point (TPoint), SmallPoint (TSmallPoint), MakeLong usw.

Ansonsten werden meistens Records zum Casten bzw. für Teilzugriffe verwendet, so wie bereits erklärt, von welchen es auch schon Fertige für Integer, Word usw. gibt.


Delphi-Quellcode:
L := (Integer(FReceiveBuffer[9]) shl 8) or FReceiveBuffer[10];
Die Klammern um SHL sind vermutlich nicht nötig, da SHL vor OR aufgelöst wird. (glaub ich)

Und das Wichtige ist der CAST des Buffer[9] auf Word oder gleich auf Integer, denn diese Typen sind schon groß genug, damit das SHL ordentlich schieben kann, ohne links überzulaufen.

Delphi.Narium 6. Sep 2018 22:30

AW: Bytes auf ein Integer auffädeln
 
Ich rate mal:

Delphi-Quellcode:
L := PInt16(@FReceiveBuffer[9])^


PInt16 ergeben 2 Byte, das heißt, das hier die Bytes 9 und 10 nach L kommen.

Bei
Delphi-Quellcode:
L := PInt32(@FReceiveBuffer[9])^
müssten es dann die Bytes 9 bis 12 sein.

p80286 6. Sep 2018 22:33

AW: Bytes auf ein Integer auffädeln
 
Oder eine ganz alte Möglichkeit:
Delphi-Quellcode:
type
  Bufferb : Array [0..127] of Byte;
  BufferW : Array [0..63] of Word absolute BufferB;
Gruß
K-H

Kostas 6. Sep 2018 22:48

AW: Bytes auf ein Integer auffädeln
 
data[9] := $0;
data[10] := $5f;

Das Ergebnis sollte sein = 95($5f)
Ich habe gerade ausprobiert, leider ist das Ergebnis nicht 95 sondern 24320($5f00)

Delphi-Quellcode:
procedure SnapshotLength;
              begin
//                FSnapshotLength := data[9];
//                FSnapshotLength := FSnapshotLength shl 8;
//                FSnapshotLength := FSnapshotLength or data[10];

                FSnapshotLength := PInt16(@data[9])^;
              end;

Delphi.Narium 6. Sep 2018 22:59

AW: Bytes auf ein Integer auffädeln
 
Was bitte ist denn FReceiveBuffer? Gibt es da zufällig eine Definition zu, so dass man weiß, wovon geredet wird?

z. B.:
Delphi-Quellcode:
FReceiveBuffer : Array[0..12345] of Byte;
FReceiveBuffer : Array[0..12345] of Integer;
FReceiveBuffer : Array[0..12345] of Char;
FReceiveBuffer : Array[0..12345] of Word;

himitsu 6. Sep 2018 23:10

AW: Bytes auf ein Integer auffädeln
 
Zitat:

Zitat von Kostas (Beitrag 1412652)
Das Ergebnis sollte sein = 95($5f)
Ich habe gerade ausprobiert, leider ist das Ergebnis nicht 95 sondern 24320($5f00)

Delphi-Referenz durchsuchenSystem.Swap
https://www.delphipraxis.net/125740-...rtauschen.html

Kostas 6. Sep 2018 23:18

AW: Bytes auf ein Integer auffädeln
 
Oh sorry Delphi.Narium,

FReceiveBuffer ist ein array of byte;
Da sind eine Menge Bytes enthalten. In diesem Paket muss ich z.B.: das Byte 9 und 10 in ein Integer kopieren. Zuerst kommt das Byte 9 und danach das Byte 10.

Als Beispiel:
FReceiveBuffer[9] := $10;
FReceiveBuffer[10] := $5f;

Wenn das Byte [9]+[10] auf ein Integer geschoben wird, sollte das Ergebnis $105f sein.

Gruß Kostas

Uwe Raabe 6. Sep 2018 23:33

AW: Bytes auf ein Integer auffädeln
 
Delphi-Quellcode:
var
  buf: LongRec;
begin
  buf.Bytes[3] := 0;
  buf.Bytes[2] := 0;
  buf.Bytes[1] := FReceiveBuffer[9];
  buf.Bytes[0] := FReceiveBuffer[10];
  Result := Integer(buf);
end;

Jasocul 7. Sep 2018 09:18

AW: Bytes auf ein Integer auffädeln
 
Ich benutze in solchen Fällen gerne variante Records:
Delphi-Quellcode:
  TMyRec = packed record
    case tag : byte of
      0 : (b1 : Byte;
           b2 : Byte;
           b3 : Byte;
           b4 : Byte);
      1 : (MyInt : Integer);
  end;
Mit deinem Beispiel müsste es dann so funktionieren:
Delphi-Quellcode:
var
  vRec : TMyRec;
begin
  vRec.MyInt := 0; // Initialisierung. Damit sind die b-Werte auch initialisiert
  vRec.b1 := $10;
  vRec.b2 := $5f;
end;
Bei der Reihenfolge der Byte-Werte weiß ich leider nicht mehr genau, wie das ganz korrekt sein muss. Ich meine, dass das Mixed Endian ist. Für das Beispiel ist es jedenfalls korrekt.
Das kannst du aber einfach prüfen, indem du Testwerte bei MyInt einträgst und nachsiehst, was bei den einzelnen Byte-Werten steht.

Einen Link, wie das in Delphi tatsächlich ist, habe ich auf die Schnelle leider nicht gefunden.

Kostas 7. Sep 2018 10:06

AW: Bytes auf ein Integer auffädeln
 
Hallo Zusammen,

Die Methode mit dem packed record gefällt mit sehr gut.
Das Ergebnis von Test1 und Test2 sind identisch.
Ich finde Test1 ist schöner zu lesen.

Eigentlich habe ich gehofft es gibt so etwas wie: MyInt := FReceiveBuffer[11] << FReceiveBuffer[12] << FReceiveBuffer[13];
Ich werde die packed record Methode einsetzen.


Delphi-Quellcode:
TMyIntRec = packed record
    case tag : byte of
      0 : (b1 : Byte;
           b2 : Byte;
           b3 : Byte;
           b4 : Byte);
      1 : (MyInt : Integer);
end;


function Test1:integer;
var MyIntRec: TMyIntRec;
begin
  MyIntRec.MyInt := 0;
  MyIntRec.b1 := FReceiveBuffer[13];
  MyIntRec.b2 := FReceiveBuffer[12];
  MyIntRec.b3 := FReceiveBuffer[11];
  result := MyIntRec.MyInt;
end;
Delphi-Quellcode:
function Test2:integer;
begin
  result := FReceiveBuffer[11];

  result := result shl 8;
  result := result or FReceiveBuffer[12];

  result := result shl 8;
  result := result or FReceiveBuffer[13];

end;

Herzlichen Dank an ALLE und einen schönen Tag.
Gruß Kostas

Zacherl 7. Sep 2018 13:57

AW: Bytes auf ein Integer auffädeln
 
Um nochmal kurz auf meinen Vorschlag zurückzukommen:
In deinem Beispiel sah es so aus, als ob du die einzelnen Bytes in identischer Reihenfolge auslesen und speichern willst (also gleiche Byte-Order), oder doch nicht? (siehe Edit). Da du die Reihenfolge jetzt augenscheinlich aber umdrehen musst, funktioniert mein Ansatz für dich leider nicht. Ansonsten wäre die Vorgehensweise folgende:
Delphi-Quellcode:
var
  I: Integer;
begin
  { 1 Byte } I := PShortInt(@FReceiveBuffer[Index])^;
  { 2 Byte } I := PSmallInt(@FReceiveBuffer[Index])^;
  { 4 Byte } I := PLongInt (@FReceiveBuffer[Index])^;
Hier würde die Ausgelesene Zahl tatsächlich auch korrekt sign-extended (im Falle von 1 und 2 Byte), wenn sie dem Integer zugewiesen wird. Also wenn im 1-Byte Falle die Zahl beispielsweise "-1" wäre, würde der Integer nach der Zuweisung ebenfalls "-1" enthalten. Anders als bei deiner manuellen Shifterei. Dort hätte der Integer dann den Wert "255". Willst du explizit keine sign-extension, dann kann man auch einfach unsigned Typen verwenden:
Delphi-Quellcode:
var
  I: Integer;
begin
  { 1 Byte } I := PByte (@FReceiveBuffer[Index])^;
  { 2 Byte } I := PWord (@FReceiveBuffer[Index])^;
  { 4 Byte } I := PDWord(@FReceiveBuffer[Index])^;
In diesem Falle würden die "überschüssigen" Bytes des Integers automatisch auf 0 gesetzt.

Edit:
Jetzt bin ich verwirrt. Einmal verwendest du die gleiche Byte-Order:
Zitat:

Byte 9 und 10 in ein Integer kopieren. Zuerst kommt das Byte 9 und danach das Byte 10.
und einmal drehst du die Reihenfolge um:
Zitat:

Delphi-Quellcode:
MyIntRec.b1 := FReceiveBuffer[13];
MyIntRec.b2 := FReceiveBuffer[12];
MyIntRec.b3 := FReceiveBuffer[11];


Kostas 7. Sep 2018 14:12

AW: Bytes auf ein Integer auffädeln
 
Sorry Zacherl,

die einzelne Bytes müssen in der Quelle NICHT direkt nacheinander liegen. Ich habe zufällig Byte 11,12,13 verwendet.
Das Ziel ist bis zu vier Bytes auf ein Integer zu schieben.
Es kommt auch vor das ich z.B.: die drei Bytes 33, 1 und 7 auf ein Integer schieben muss.

Gruß Kostas

Zacherl 7. Sep 2018 14:15

AW: Bytes auf ein Integer auffädeln
 
Ahh, okay dann macht es Sinn :-D In dem Falle ist meine Vorgehensweise natürlich hinfällig.

Uwe Raabe 7. Sep 2018 14:41

AW: Bytes auf ein Integer auffädeln
 
Probier doch mal folgende Funktion aus:
Delphi-Quellcode:
function MakeInteger(const Bytes: array of Byte): Integer;
var
  buf: LongRec;
  I: Integer;
  N: Integer;
begin
  Integer(buf) := 0;
  N := Length(Bytes) - 1;
  Assert(N < 4, 'mehr als vier Bytes übergeben');
  for I := 0 to N do begin
    buf.Bytes[N - I] := Bytes[I];
  end;
  Result := Integer(buf);
end;

// Aufruf:
MyInt := MakeInteger([FReceiveBuffer[9], FReceiveBuffer[10]]);

Kostas 7. Sep 2018 15:16

AW: Bytes auf ein Integer auffädeln
 
Perfekt Uwe,

genau das habe ich gemeint. Bau gerne wieder alles um.

Herzlichen Dank an Euch. :-)


Alle Zeitangaben in WEZ +1. Es ist jetzt 03:46 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz