Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Konvertierung von BigEndian-Werten (https://www.delphipraxis.net/169483-konvertierung-von-bigendian-werten.html)

p80286 23. Jul 2012 13:16

Konvertierung von BigEndian-Werten
 
Hallo zusammen,

ich muß BigEndian-Werte aus einer Datei auslesen und dann "normal" weiter verarbeiten.
Dafür nutze ich folgende Routine
Delphi-Quellcode:
type
  ta4 = array [0..3] of byte;
  tpa4= ^ta4;

function Big2Little32(ina:tpa4):integer;
begin
  result:=ina[3]+
          ina[2] shl 8+
          ina[1] shl 16+
          ina[0] shl 24;
end;
Für 24 und 16Bit-Werte existieren entsprechende Routinen.

Ist dieser Weg (nahezu) optimal oder gibt es einen besseren? ggf nur eine Routine für mehrere Größen(16,24,32...Bit)?

Gruß
K-H

guinnes 23. Jul 2012 13:18

AW: Konvertierung von BigEndian-Werten
 
Was hältst du von einem Varianten Record ? Damit würdest du die schieberei sparen

p80286 23. Jul 2012 13:24

AW: Konvertierung von BigEndian-Werten
 
hast Du ein Beispiel?
Meiner Meinung nach komme ich um die Schieberei auf kenen Fall herum?

Gruß
K-H

jfheins 23. Jul 2012 13:34

AW: Konvertierung von BigEndian-Werten
 
Naja, also kürzer ginge es wohl schon:
Delphi-Quellcode:
function SwapInt32(Value: Integer): LongWord; register;
asm
  BSWAP EAX
end;

function SwapInt16(Value: SmallInt): SmallInt; register;
asm
  XCHG EAX
end;
Ob das schneller ist? Kann sein. Weniger Funktionen ist es leider nicht - das wäre aber auch mit zusätzlichem Aufwand verbunden...
(Code ungetestet, ich kenne mich nicht besonders mit Assembler aus...)

Bummi 23. Jul 2012 13:36

AW: Konvertierung von BigEndian-Werten
 
Delphi-Quellcode:
function Swap(Value: Cardinal): Cardinal;
  asm
     BSWAP EAX
  end;
// gibts auch noch:

function SwapUInt64(X: UInt64): UInt64;
asm
  mov EDX,dword ptr [X]
  mov EAX,dword ptr [X+4]
  bswap EDX
  bswap EAX
end;

guinnes 23. Jul 2012 13:39

AW: Konvertierung von BigEndian-Werten
 
Delphi-Quellcode:
TConvert = Record
  case integer of
    0 : (Bytes : Array[0..3] of Byte);
    1 : (MyInt : Integer);
end;

function Big2Little32(ina:tpa4):integer;
var
  lConvert : TConvert;
begin
  lConvert.Bytes[0] := ima[3];
  lConvert.Bytes[1] := ina[2];
  lConvert.Bytes[2] := ina[1];
  lConvert.Bytes[3] := ina[0];
  Result ;) lConvert.MyInt;
end;

himitsu 23. Jul 2012 13:45

AW: Konvertierung von BigEndian-Werten
 
Ansosnten wohl eher OR, anstatt +.
Delphi-Quellcode:
function Big2Little32(ina: tpa4): LongInt;
begin
  Result:=ina[3] or
          ina[2] shl 8 or
          ina[1] shl 16 or
          ina[0] shl 24;
end;
Und falls man Assembler nutzt, muß man später auch noch die 64-Bit-Version basteln, denn in Win64 sind die Register anders belegt.

p80286 23. Jul 2012 15:15

AW: Konvertierung von BigEndian-Werten
 
Vielen Dank!
Da hab ich ja jetzt etwas zum ausprobieren.

@Himitsu
Ich denke Deiner Version würde noch ein
Delphi-Quellcode:
Result:=0;
ganz gut passen.
(was man mit OR so assoziiert..)

Da ich mit ASM seit Jahren nichts mehr gemacht habe, mal sehen was daraus wird.

Vielen Dank nochmal

K-H

himitsu 23. Jul 2012 15:55

AW: Konvertierung von BigEndian-Werten
 
Zitat:

Zitat von p80286 (Beitrag 1175686)
Ich denke Deiner Version würde noch ein
Delphi-Quellcode:
Result:=0;
ganz gut passen.
(was man mit OR so assoziiert..)

Aber nur wenn man das Result auch mit ein-or-t
Delphi-Quellcode:
Result := Result or ...

Und wenn, dann hätte man das beim + auch schon mit machen müssen. :angle:

Hier werden ja nur die 4 ina's ver-or-t und ich hoffe mal diese sind ordentlich initialisiert.

SirThornberry 23. Jul 2012 16:27

AW: Konvertierung von BigEndian-Werten
 
Wenn du nicht für alles eine eigene Funktion willst könntest du auch einen pointer auf die Daten + die Datengröße übergeben und anhand dessen dann entsprechend viele Bytes switchen

p80286 25. Jul 2012 14:25

AW: Konvertierung von BigEndian-Werten
 
Liste der Anhänge anzeigen (Anzahl: 3)
Hallo und vielen Dank nochmal auch an Mr OR!
Ich habe alle Anregungen (sofern ich sie verstanden habe) einmal verwurstet und versucht sie an Hand eines Benchmarks zu beurteilen.

Delphi-Quellcode:
function Big2Little32c(ina:tpa4):integer;
var
  dd : integer;
begin
  dd:= ina^[3]+
      (ina^[2] shl 8)+
      (ina^[1] shl 16)+
      (ina^[0] shl 24);
  result:=dd;
end;

function Big2Little32H(ina:tpa4):integer;
begin
  result:=0;
  result:= result or
           ina[3] or
          (ina[2] shl 8) or
          (ina[1] shl 16) or
          (ina[0] shl 24);
end;

function Big2Little32R(ina:tpa4):integer;
type
  tLittRec=record
         case integer of
         1 : (wert:integer);
         2 : (aa: array [0..3] of byte);
  end;
var
  my : tLittRec ;
begin
  my.wert:=0;
  my.aa[0]:=ina[3];
  my.aa[1]:=ina[2];
  my.aa[2]:=ina[1];
  my.aa[3]:=ina[0];
  result:=my.wert;
end;

function SwapInt32(Value: Integer): integer; register;
asm
  BSWAP EAX
end;
Big2Little32c/function Big2Little32H sind etwa gleich schnell (im Rahmen der Messgenauigkeit)
SwapInt32 ist etwas schneller(-10%)
Big2Little32R(ina:tpa4):integer;
Braucht ca. die dreifache Zeit.

Da ich nur ca 1000-3000 Werte lesen muß ist der Unterschied eigentlich irrelevant, aber in diesem Falle ist small beautiful and fast.

Ich werde SirThornberrys Anregung aufgreifen und da noch ein "LängenMäntelchen" um legen, dann hab ich was ich will.

Vielen Dank nochmal
K-H

Falls es jemanden interessiert, im Anhang das Programm und die erhaltenen Werte.

himitsu 25. Jul 2012 16:11

AW: Konvertierung von BigEndian-Werten
 
Wobei du in Big2Little32R unnötig viel umkopierst.
Und da du sowieso alle Bytes wieder überschreibst, muß es auch nicht initialisiert werden (wert=0)
Delphi-Quellcode:
function Big2Little32R(ina:tpa4):integer;
type
  tLittRec=record
         case integer of
         2 : (aa: array [0..3] of byte);
  end;
var
  my : tLittRec absolute Result;
begin
  my.aa[0]:=ina[3];
  my.aa[1]:=ina[2];
  my.aa[2]:=ina[1];
  my.aa[3]:=ina[0];
end;

function Big2Little32R(ina:tpa4):integer;
type
  tLittRec= array [0..3] of byte;
var
  my : tLittRec absolute Result;
begin
  my[0]:=ina[3];
  my[1]:=ina[2];
  my[2]:=ina[1];
  my[3]:=ina[0];
end;

function Big2Little32R(ina: tpa4): LongInt;
var
  res: tpa4 absolute Result;
begin
  res[0] := ina[3];
  res[1] := ina[2];
  res[2] := ina[1];
  res[3] := ina[0];
end;

function Big2Little32R(ina: tpa4): LongInt;
begin
  tpa4(Result)[0] := ina[3];
  tpa4(Result)[1] := ina[2];
  tpa4(Result)[2] := ina[1];
  tpa4(Result)[3] := ina[0];
end;
Wobei alle Vier im Prinzip auf's Selbe rauslaufen, also nach dem Kompilieren.

p80286 25. Jul 2012 16:40

AW: Konvertierung von BigEndian-Werten
 
Dumme Frage
Delphi-Quellcode:
type
  tLittRec=record
         case integer of
         2 : (aa: array [0..3] of byte);
  end;
Fehlt der Integer absichtlich?
(das absolute finde ich stark, oft eingesetzt aber nie so!)

Gruß
K-H

himitsu 25. Jul 2012 16:43

AW: Konvertierung von BigEndian-Werten
 
Du hattest das 1:Integer ja nur für
Delphi-Quellcode:
my.wert:=0;
benutzt.
Und da dieses nun weg war, wurde 1:Integer auch nicht mehr benötigt. :angle:

p80286 25. Jul 2012 16:53

AW: Konvertierung von BigEndian-Werten
 
Nee da war noch
Delphi-Quellcode:
result:=aa.wert;
aber egal, auf jeden Fall ein Beispiel, das es viele Wege gibt.

Gruß
K-H

himitsu 25. Jul 2012 17:20

AW: Konvertierung von BigEndian-Werten
 
:oops: ganz vergessen :lol:

Nicht nur viele Wege ... auch viele Ansichten

Alle meine 4 Funktionen machen ganz genau das Selbe, also wenn man es Speichertechnisch betrachtet.
Nur daß der Quellcode anders aussieht, auch wenn er, wie gesagt, genau das Selbe macht.

Amateurprofi 26. Jul 2012 00:43

AW: Konvertierung von BigEndian-Werten
 
Oder so.
Der Compiler wird sich die richtige Funktion selber suchen.

Delphi-Quellcode:
FUNCTION ChangeEndian(value:Word):Word; overload;
asm
   {$IFDEF CPUX64}
   mov  rax,rcx
   {$ENDIF}
   XCHG al,ah
end;

FUNCTION ChangeEndian(value:DWord):DWord; overload;
asm
   {$IFDEF CPUX64}
   mov  rax,rcx
   {$ENDIF}
   bswap eax
end;

FUNCTION ChangeEndian(const value:UInt64):UInt64; overload;
asm
   {$IFDEF CPUX64}
   mov  rax,rcx
   bswap rax
   {$ELSE}
   mov edx,[esp+8]
   mov eax,[esp+12]
   bswap eax
   bswap edx
   {$ENDIF}
end;

FUNCTION ChangeEndian(value:SmallInt):SmallInt; overload;
asm
   {$IFDEF CPUX64}
   mov  rax,rcx
   {$ENDIF}
   XCHG al,ah
end;

FUNCTION ChangeEndian(value:Integer):Integer; overload;
asm
   {$IFDEF CPUX64}
   mov  rax,rcx
   {$ENDIF}
   bswap eax
end;

FUNCTION ChangeEndian(const value:Int64):Int64; overload;
asm
   {$IFDEF CPUX64}
   mov  rax,rcx
   bswap rax
   {$ELSE}
   mov edx,[esp+8]
   mov eax,[esp+12]
   bswap eax
   bswap edx
   {$ENDIF}
end;

Furtbichler 26. Jul 2012 06:08

AW: Konvertierung von BigEndian-Werten
 
Funktioniert der Compilerswitch auch zur Laufzeit?

Bummi 26. Jul 2012 06:36

AW: Konvertierung von BigEndian-Werten
 
welche Anwendung wechselt zu Laufzeit zwischen 32 und 64 Bit-Anwendung?

Amateurprofi 26. Jul 2012 11:31

AW: Konvertierung von BigEndian-Werten
 
Zitat:

Zitat von Furtbichler (Beitrag 1175947)
Funktioniert der Compilerswitch auch zur Laufzeit?

Ja, selbstverständlich.


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:42 Uhr.

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