Open Array versus type Array [gelöst]

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1629
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Open Array versus type Array [gelöst]

Beitrag von corpsman »

Servus,

Ich hab hier folgende Routinen :

Code: Alles auswählen

 
 
Procedure TIrgendwas.WriteBytes(Const data: Array Of Byte);
 
procedure TIrgendwas2.WriteByteArr(const Data: TBytes);
 
 
Nun will ich von TIrgendwas die Daten an TIrgendwas2 weiter leiten :

Darf ich das so machen ? (Der Compiler akzeptiert es, zumindest)

Code: Alles auswählen

 
Procedure TIrgendwas.WriteBytes(Const data: Array Of Byte);
begin
  InstanzvonTIrgendwas2.WriteBytes(@data[0]);
end;
 
Alternativ hätte ich noch die (schlechteren, weil Langsameren Varianten)
v1:

Code: Alles auswählen

 
Procedure TIrgendwas.WriteBytes(Const data: Array Of Byte);
Var
  b: TBytes;
Begin
  setlength(b, length(data));
  Move(data[0], b, length(data));
  InstanzvonTIrgendwas2.WriteByteArr(b);
  setlength(b, 0); 
end;
 
oder ganz vorsichtig v2:

Code: Alles auswählen

 
Procedure TIrgendwas.WriteBytes(Const data: Array Of Byte);
Var
  b: TBytes;
  i:integer;
Begin
  setlength(b, length(data));
  for i := low(data) to high(data) do
     b[i-low(data)] := data[i];
  InstanzvonTIrgendwas2.WriteByteArr(b);
  setlength(b, 0); 
end;
 
[Edit : Nach einigem Ausprobieren, scheint wohl nur V2 zu funktionieren..]
Zuletzt geändert von corpsman am Di 18. Nov 2014, 17:18, insgesamt 1-mal geändert.
--
Just try it

soerensen3
Beiträge: 104
Registriert: Fr 22. Jun 2012, 01:51
OS, Lazarus, FPC: Fedora-Linux 23 (Korora) Lazarus 1.6 FPC 3.0
CPU-Target: 64Bit
Wohnort: Bonn

Re: Open Array versus type Array

Beitrag von soerensen3 »

Probier mal bei Variante 1:
Move(data[0], b[ 0 ], length(data));
Wenn du nur b verwendest, zeigt das glaube ich auf length( b )
und nicht auf das erste Element von B.

Falls das nicht geht, probier mal das:

Code: Alles auswählen

 
Procedure TIrgendwas.WriteBytes(Const data: Array Of Byte);
Var
  b: PByte;
type
  TByteArray = array of Byte;
Begin
  GetMem( b, SizeOf( Byte ) * Length( Data ));
  Move(data[0], b[ 0 ], length(data));
  InstanzvonTIrgendwas2.WriteByteArr( TByteArray( b));
  FreeMem( b, SizeOf( Byte )); 
end;
 

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1629
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Open Array versus type Array

Beitrag von corpsman »

das hier geht :

Code: Alles auswählen

 
Procedure TUartInput.WriteBytes(Const data: Array Of Byte);
Var
  b: TBytes;
  i: integer;
Begin
  setlength(b, length(data));
  move(data[0], b[0], length(data));
  FUart.WriteByteArr(b);
  setlength(b, 0);
End;
 
ist getmem schneller als setlength ?
--
Just try it

ruewa
Beiträge: 153
Registriert: Sa 12. Apr 2014, 14:43

Re: Open Array versus type Array

Beitrag von ruewa »

Hallo Corpsman,
corpsman hat geschrieben:Ich hab hier folgende Routinen :

Code: Alles auswählen

 
Procedure TIrgendwas.WriteBytes(Const data: Array Of Byte);
procedure TIrgendwas2.WriteByteArr(const Data: TBytes); 
Warum verwendest Du zwei synonyme Deklarationen? TBytes ist seinerseits definiert als Array of Byte. Dem Compiler ist das egal, aber unter Konsistenzgesichtspunkten finde ich das, sagen wir mal, unschön bzw. verwirrend.
soerensen3 hat geschrieben:Probier mal bei Variante 1:
Move(data[0], b[ 0 ], length(data));
corpsman hat geschrieben:das hier geht :

Code: Alles auswählen

Var
  b: TBytes;
  i: integer;
Begin
  setlength(b, length(data));
  move(data[0], b[0], length(data));
  ...
End;
Jein! Es funktioniert in diesem Sonderfall, weil Sizeof(Byte) 1 ist. Ansonsten ist das gefährlich.
Zunächst mal: Eine Open-Array-Variable. also in Deinem Fall b, wird intern als Pointer behandelt (egal welche Deklarationsvariante Du verwendest), Sizeof(b) ergibt SizeOf(Pointer). Move(data, b, Length(b) würde also schlicht den Pointer auf data mit dem Pointer auf b überschreiben. Insofern bezeichnet Data[0] das erste Element, deshalb ist das richtig so.
Length(b) ergibt wiederum die Anzahl der Elemente des Arrays, d.h. der Speicherbedarf errechnet sich bei Open Arrays also immer aus (Length(array) * SizeOf(Elementtyp)).
corpsman hat geschrieben:ist getmem schneller als setlength ?
Wieviele hundert Milllionen Mal willst Du das durchführen, bevor sich dort etwahige Laufzeitunterschiede bemerkbar machen?

Gruß Rüdiger

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1629
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Open Array versus type Array

Beitrag von corpsman »

Warum verwendest Du zwei synonyme Deklarationen? TBytes ist seinerseits definiert als Array of Byte. Dem Compiler ist das egal, aber unter Konsistenzgesichtspunkten finde ich das, sagen wir mal, unschön bzw. verwirrend.
Weil ich hier unterschiedlichen Komponenten nutze, und der Entwickler dieser hat das halt so deklariert (klar ich könnte den Source anpassen, den hab ich ja, aber ...)
In meinem Mini Sample sieht das natürlich doof aus, das ist mir schon klar.
Jein! Es funktioniert in diesem Sonderfall, weil Sizeof(Byte) 1 ist. Ansonsten ist das gefährlich.
Normalerweise hätte ich geschrieben :

Code: Alles auswählen

 
setlength(b, length(data)* sizeof(byte));
 
aber wie du schon richtig gesehen hast ist das ja 1.
Wieviele hundert Milllionen Mal willst Du das durchführen, bevor sich dort etwahige Laufzeitunterschiede bemerkbar machen?
Ich rufe es ca. 1 mal alle 10s auf. Es geht hier mehr darum zu erfahren warum soerensen3 getmem anstelle von setlength nutzt.
--
Just try it

ruewa
Beiträge: 153
Registriert: Sa 12. Apr 2014, 14:43

Re: Open Array versus type Array

Beitrag von ruewa »

corpsman hat geschrieben:Weil ich hier unterschiedlichen Komponenten nutze, und der Entwickler dieser hat das halt so deklariert.
Alles klar! Sorry, das hatte ich nicht gesehen.
corpsman hat geschrieben:Normalerweise hätte ich geschrieben :

Code: Alles auswählen

setlength(b, length(data)* sizeof(byte));
aber wie du schon richtig gesehen hast ist das ja 1.
Okay, solange Du weißt, was Du tust, ist diese Abkürzung ja in Ordnung. Bloß andere, die das lesen, könnten dadurch leicht aufs falsche Gleis gesetzt werden.
corpsman hat geschrieben:Es geht hier mehr darum zu erfahren warum soerensen3 getmem anstelle von setlength nutzt.
Das habe ich auch nicht verstanden. SetLength nutzt natürlich getmen, ist aber schon noch etwas komplexer:

Code: Alles auswählen

procedure DynArraySetLength(var a: Pointer; typeInfo: Pointer; dimCnt: SizeInt; lengthVec: PSizeInt);
  var
    preallocated : array[0..10] of SizeInt;
    i : SizeInt;
    p : PSizeInt;
  begin
    if dimCnt<=high(preallocated)+1 then
      p:=@preallocated[0]
    else
      getmem(p,sizeof(SizeInt)*dimCnt);
    for i:=0 to dimCnt-1 do
      p[i]:=lengthVec[dimCnt-1-i];
    int_dynarray_setlength(a,typeInfo,dimCnt,p);
    if p<>@preallocated[0] then
      freemem(p);
  end;
Das ist (bei mir unter Linux) in /usr/share/fpcsrc/2.6.4/rtl/inc/dynarr.inc. Ich jedenfalls würde die Konsequenzen nicht überblicken, dieses schnell mal von Hand abzukürzen.

Gruß Rüdiger

soerensen3
Beiträge: 104
Registriert: Fr 22. Jun 2012, 01:51
OS, Lazarus, FPC: Fedora-Linux 23 (Korora) Lazarus 1.6 FPC 3.0
CPU-Target: 64Bit
Wohnort: Bonn

Re: Open Array versus type Array

Beitrag von soerensen3 »

Habe GetMem nur vorgeschlagen, weil ich mir das erst überlegt hatte und dann dabei gemerkt habe dass in deinem Code das b[0] gefehlt hat. Da hatte ich das andere schon geschrieben. Hatte aber keine besonderen Gründe. Konnte den Code auch gerade nicht testen, dann hab ich es als Alternative drin gelassen.
SetLength ist aber übersichtlicher, würde an deiner Stelle das nehmen.

Gruß Johannes

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1629
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Open Array versus type Array [gelöst]

Beitrag von corpsman »

*g*

Abschließend kann man also sagen, ich komme nicht darum die Daten zu "Kopieren", da es wohl keine direkte "uminterpretierung" der daten gibt.
--
Just try it

ruewa
Beiträge: 153
Registriert: Sa 12. Apr 2014, 14:43

Re: Open Array versus type Array [gelöst]

Beitrag von ruewa »

corpsman hat geschrieben:Abschließend kann man also sagen, ich komme nicht darum die Daten zu "Kopieren", da es wohl keine direkte "uminterpretierung" der daten gibt.
Entschuldige, vielleicht stehe ich gerade auf dem Schlauch, aber was meinst Du mit "Uminterpretierung"?

Du hast schon zwei Möglichkeiten: Du kannst natürlich eine zweite (z.B. eine lokale) Variable auf Dein schon existierendes Array setzen, dann hast Du ein Array und zwei Variablen, die (intern) identische Zeiger auf dieses Array enthalten. Oder noch einfacher, Du übergibst das Array kurzerhand als var (statt als const), dann kannst Du die Daten auch weiterbearbeiten. Oder Du brauchst, aus welchen Gründen auch immer, zwei getrennte Arrays (z.B. weil Du in einem die Daten verändern willst, die Ausgangsdaten aber erhalten bleiben sollen), dann mußt Du natürlich erstmal eine Kopie anfertigen.

Könnte es sein, daß Dein Problem bei Licht besehen die Übergabe des Arrays als const ist?

Gruß Rüdiger

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: Open Array versus type Array [gelöst]

Beitrag von Michl »

corpsman hat geschrieben:*g*

Abschließend kann man also sagen, ich komme nicht darum die Daten zu "Kopieren", da es wohl keine direkte "uminterpretierung" der daten gibt.
Warum nicht so?!

Code: Alles auswählen

procedure TIrgendwas.WriteBytes(const data: array of Byte);
begin
  InstanzvonTIrgendwas2.WriteByteArr(TBytes(@data));
end;
ruewa hat geschrieben:Entschuldige, vielleicht stehe ich gerade auf dem Schlauch, aber was meinst Du mit "Uminterpretierung"?
Die übergebenen Parameter sind nicht identisch. Siehe: der Hinweis bei http://docwiki.embarcadero.com/RADStudi ... -Parameter

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Open Array versus type Array

Beitrag von Socke »

corpsman hat geschrieben:Normalerweise hätte ich geschrieben :

Code: Alles auswählen

setlength(b, length(data)* sizeof(byte));
aber wie du schon richtig gesehen hast ist das ja 1.
ACHTUNG: Ganz großer Unsinn!
SetLength() nimmt die Anzahl der Elemente im Array entgegen; nicht die Gesamtgröße in Bytes. Es wäre schlicht unsinning, einen array of qword auf die Länge 3 zu setzen...

Richtig ist diese Formel hingegen bei Move(). Hier wird direkt auf Byte-Ebene gearbeitet.

Code: Alles auswählen

Move(data[0], b[0], length(data)*sizeof(data[0]));
Die Funktion SizeOf() wird bereits vom Compiler durch den korrekten Wert (hier 1) ersetzt. Die Multiplikation mit 1 sollte dann der Peephole-Optimizer entfernen, bevor dein Programm endgültig übersetzt wird (vorausgesetzt er wurde nicht ausgeschaltet).
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

ruewa
Beiträge: 153
Registriert: Sa 12. Apr 2014, 14:43

Re: Open Array versus type Array

Beitrag von ruewa »

Socke hat geschrieben:ACHTUNG: Ganz großer Unsinn!
SetLength() nimmt die Anzahl der Elemente im Array entgegen; nicht die Gesamtgröße in Bytes.
Oh, verdammt, Du hast recht! Sorry für den Fehler, ich hatte das aus dem Gedächtnis verwechselt mit der FillChar-Problematik: http://wiki.freepascal.org/Talk:Dynamic_array

Ist aber auch ein vertrackter Kram!

Gruß Rüdiger

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1629
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Open Array versus type Array [gelöst]

Beitrag von corpsman »

Danke Michl, deine Variante funktioniert

Code: Alles auswählen

 
// Richtig
InstanzvonTIrgendwas2.WriteBytes(TBytes(@data));  // So gehts, weil der "Pointer" convertiert wird
InstanzvonTIrgendwas2.WriteBytes(@data);  // So gehts auch
 
// Falsch
InstanzvonTIrgendwas2.WriteBytes(@data[0]); // So wird die Addresse des 1. Elementes übergeben und nicht der Pointer
 
--
Just try it

Antworten