Variable als Integer und als String(oder Binär <> Hex)
Variable als Integer und als String(oder Binär <> Hex)
Hallo Lazarusgemeinde
Ich möchte für Matroska die Specs nochmal nachprogrammieren und dort gibt es Felder die als Interger deklariert sind.
Liest man solche Felder direkt aus einer Matroska Datei aus erhält man logischerweise einen Integer.
Den Wert kann man einfach in einer Variablen speichern.
Allerdings wird dann sehr oft dieser Interger als String benötigt. Zum anzeigen in der GUI und sogar als ausgabe in einer XML Datei.
Klar könnte ich wann immer der Integer als String benötigt wird, ein "IntToStr()" ausführen. Aber dies wäre sehr sehr oft (in der GUI beim VTV zum beispiel).
Würde es sinn machen ein Record oder Klasse zu verwenden wo man eine Int-var und eine String-var hat?
Beim setzen des Integer Wertes wird dann automatisch der String-Wert erzeugt und umgekehrt.
Oder gibt es da noch bessere Möglichkeiten?
Ich möchte für Matroska die Specs nochmal nachprogrammieren und dort gibt es Felder die als Interger deklariert sind.
Liest man solche Felder direkt aus einer Matroska Datei aus erhält man logischerweise einen Integer.
Den Wert kann man einfach in einer Variablen speichern.
Allerdings wird dann sehr oft dieser Interger als String benötigt. Zum anzeigen in der GUI und sogar als ausgabe in einer XML Datei.
Klar könnte ich wann immer der Integer als String benötigt wird, ein "IntToStr()" ausführen. Aber dies wäre sehr sehr oft (in der GUI beim VTV zum beispiel).
Würde es sinn machen ein Record oder Klasse zu verwenden wo man eine Int-var und eine String-var hat?
Beim setzen des Integer Wertes wird dann automatisch der String-Wert erzeugt und umgekehrt.
Oder gibt es da noch bessere Möglichkeiten?
Zuletzt geändert von hubblec4 am Mo 30. Sep 2019, 15:22, insgesamt 1-mal geändert.
Re: Variable als Integer und als String
Du müsstest schon SEHR VIELE Integer haben, um das in der Geschwindigkeit zu merken.
Re: Variable als Integer und als String
OK, also meinst du ich sollte da immer nach String umwandeln für Anzeigen in der GUI. Und beim parsen einer XML die String-Zahl in Integer umwandeln.
Was ist dann aber mit Elementen die als Binary deklariert sind.
Da habe ich bis jetzt eine variable als String definiert und wandel alle Bytes in einen Hex String um. Das ist dann schon aufwendiger als nur von Int-nach-String.
Was ist dann aber mit Elementen die als Binary deklariert sind.
Da habe ich bis jetzt eine variable als String definiert und wandel alle Bytes in einen Hex String um. Das ist dann schon aufwendiger als nur von Int-nach-String.
-
- Beiträge: 2118
- Registriert: Di 23. Sep 2014, 17:46
- OS, Lazarus, FPC: Win10 | Linux
- CPU-Target: x86_64
Re: Variable als Integer und als String
Wahrscheinlich geht das konvertieren von Int nach String schneller als das zeichnen des GUI's nachdem du den wert irgendwo reinschreibst. Mach dir darum keine gedanken. Solltest du massive performanceprobleme bekommen kannst du nochmal drüber nachdenken, aber vor erst machs einfach mal.
Re: Variable als Integer und als String
Speichere diese lieber in einem Array of Byte (TBytes) ab. An Daten, die als "string" gespeichert sind, kann FPC leicht Konvertierungen vornehmen, so dass die Original-Bytefolge zerstört werden kann.hubblec4 hat geschrieben:Was ist dann aber mit Elementen die als Binary deklariert sind.
Da habe ich bis jetzt eine variable als String definiert und wandel alle Bytes in einen Hex String um.
Re: Variable als Integer und als String
Ja, TBytes wäre auch meine erste wahl für diese art von Elementen. Aber dort wäre dann eine Umwandlung von TBytesToHexString notwenig und das denke ich mal ist schon etwas mehr Aufwand als IntToStr();wp_xyz hat geschrieben:Speichere diese lieber in einem Array of Byte (TBytes) ab. An Daten, die als "string" gespeichert sind, kann FPC leicht Konvertierungen vornehmen, so dass die Original-Bytefolge zerstört werden kann.hubblec4 hat geschrieben:Was ist dann aber mit Elementen die als Binary deklariert sind.
Da habe ich bis jetzt eine variable als String definiert und wandel alle Bytes in einen Hex String um.
Desweiteren gibt es noch Zeit-Elemente die als Integer deklariert sind und Nanosekunden bedeuten und müssen dann in einen Timestamp umgewandelt werden (für die Anzeige in der GUI und im XML) als: Beispiel 1000000000 = 1 sekunde = 00:00:01.000000000.
Hierzu habe ich bis jetzt zwei variablen definiert einmal als Int64 und eine als String;
Re: Variable als Integer und als String(oder Binär <> Hex)
Ich habe mal doch eine Klasse für mein Binary-HexString gebastelt und wollte fragen was ihr davon haltet.
Code: Alles auswählen
type
TBinary = class
strict private // procedures
(* setter *)
procedure SetHex(const hex: String);
procedure SetBytes(const bytes_: TBytes);
private // vars
FBytes : TBytes;
FHex : String;
//FText : String;
public // procedures
constructor Create;
destructor Destroy; override;
function Copy_Binary(const CopyTo: TBinary = nil): TBinary;
public // properties
property Hex: String read FHex write SetHex;
property Bytes: TBytes read FBytes write SetBytes;
end;
implementation
(* TBinary *)
(*============ strict private ================================================*)
(* setter *)
// Set Hex
procedure TBinary.SetHex(const hex: String);
var
b,l: Integer;
begin
FHex:=hex;
if FHex = '' then
begin
SetLength(FBytes,0);
Exit;
end;
l:=Length(FHex) div 2;
SetLength(FBytes,l);
for b:=0 to l -1 do
FBytes[b]:=StrToInt('$'+FHex[b*2]+FHex[b*2+1]);
end;
// Set Bytes
procedure TBinary.SetBytes(const bytes_: TBytes);
var
b: Integer;
begin
FBytes:=Copy(bytes_,0,MaxInt);
FHex:='';
for b:=0 to High(FBytes) do
FHex:=FHex + IntToHex(FBytes[b],2);
end;
(*============ public ========================================================*)
// Constructor
constructor TBinary.Create;
begin
inherited Create;
end;
// destructor
destructor TBinary.Destroy;
begin
SetLength(FBytes,0);
FHex:='';
inherited Destroy;
end;
// Copy TBinary
function TBinary.Copy_Binary(const CopyTo: TBinary = nil): TBinary;
begin
if CopyTo = nil then
Result:=TBinary.Create
else
Result:=CopyTo;
Result.FBytes:=Copy(FBytes,0,MaxInt);
Result.FHex:=FHex;
end;
Re: Variable als Integer und als String(oder Binär <> Hex)
Also ehrlich gesagt, ich halte das Doppel-Gemoppel für übertrieben. Wie oft wird denn die String-Konvertierung für ein und dasselbe Element aufgerufen? Wenn das nur wenige Male ist, schaffst du dir damit einen gewaltigen Overhead an Verwaltung und Speicherbedarf, ohne dass man irgendwas an Geschwindigkeitsgewinn merkt.
Re: Variable als Integer und als String(oder Binär <> Hex)
Also so ein Binary Werte wird in ein Edit Feld geladen wo dann der HexString drin steht.
Der User kann diesen String verändern, dabei wird auf gültigkeit geprüft.
In einem VTV wird dieser Wert in einer Spalte dargestellt und dort wird GetText sehr sehr oft aufgerufen. Schon wenn man mit der Mouse über den Node geht wird GetText 10 mal oder so aufgerufen.
Der User kann diesen String verändern, dabei wird auf gültigkeit geprüft.
In einem VTV wird dieser Wert in einer Spalte dargestellt und dort wird GetText sehr sehr oft aufgerufen. Schon wenn man mit der Mouse über den Node geht wird GetText 10 mal oder so aufgerufen.
-
- Beiträge: 2118
- Registriert: Di 23. Sep 2014, 17:46
- OS, Lazarus, FPC: Win10 | Linux
- CPU-Target: x86_64
Re: Variable als Integer und als String(oder Binär <> Hex)
hubblec4 hat geschrieben:In einem VTV wird dieser Wert in einer Spalte dargestellt und dort wird GetText sehr sehr oft aufgerufen. Schon wenn man mit der Mouse über den Node geht wird GetText 10 mal oder so aufgerufen.
Code: Alles auswählen
program test;
{$mode objfpc}{$H+}
uses
sysutils;
var
s: LongWord;
i: Integer;
j: LongInt;
str: array of String;
begin
SetLength(str, 10000001);
for i:=0 to 10000000 do
str[i]:= IntToStr(Random(2000000000));
s := GetTickCount;
for i:=0 to 10000000 do
j:= StrToInt(str[i]);
WriteLn(GetTickCount-s);
ReadLn;
end.
Und wenn du dir über performance gedanken machst, denk mal drüber nach wann und wo Speicher alloziiert werden muss, denn das ist tatsächlich teuer. Bei deinem Code z.B.
Code: Alles auswählen
'$'+FHex[b*2]+FHex[b*2+1]
Code: Alles auswählen
FHex:=FHex + IntToHex(FBytes[b],2);
Wenn du das effizient machen willst würde ich es so machen:
Code: Alles auswählen
function HexCharToHalfByte(const c: Char): Byte; inline;
begin
case c of
'0'..'9': Result := ord(c) - ord('0');
'A'..'F': Result := ord(c) - ord('A') + 10;
else raise EFormatError.Create('Not a Hex char');
end;
end;
function HexToBytes(Hex: String): TBytes;
var
i: Integer;
begin
Hex := Hex.ToUpper; // sicher gehen das es auf jeden fall uppercase ist
// Speicheralloziieren
SetLength(Result, Hex.Length div 2);
for i:=0 to High(Result) do
Result[i] := (HexCharToHalfByte(Hex.Chars[i*2]) shl 4) + HexCharToHalfByte(Hex.Chars[i*2 + 1]);
end;
function HalfByteToHex(const hb: Byte): Char; inline;
begin
case hb of
0..9: Result := chr(hb + ord('0'));
10..15: Result := chr(hb - 10 + ord('A'));
else raise EFormatError.Create('Not a Halfbyte');
end;
end;
function BytesToHex(const Bytes: TBytes): String;
var
i: Integer;
begin
SetLength(Result, Length(Bytes) * 2);
for i:=0 to High(Bytes) do
begin
Result[i*2 + 1] := HalfByteToHex(Bytes[i] shr 4);
Result[i*2 + 2] := HalfByteToHex(Bytes[i] And $0F);
end;
end;
PS:
Code: Alles auswählen
SetLength(FBytes,0);
FHex:='';
Und ich persönlich würde die methode Copy_Binary zu AssignTo umbenennen, um die Pascal typischen Namenskonvention einzuhalten (eventuell macht es für dich sogar direkt sinn von TPersitent abzuleiten, wenn dein Objekt kopierbar ist)
Re: Variable als Integer und als String(oder Binär <> Hex)
Das mit dem Integer und String ist völlig klar nun, Danke.
Ebenso das umwandeln von Hex nach TBytes und zurück. Hatte diese Umwandlungen von diversen Webseiten mir abgeschaut.
Deine 4 Funktionen sind sicher besser und ich kann die ja nehmen.
Also keine doppelte Datenhaltung, dafür lieber immer bissl rechnen.
Wegen dem Constructor und destructor:
Wenn da nichts drin steht ausser inherited dann gleich weglassen.
Ich hatte bei meinem Programm beobachtet das es immer mehr Speicher will je mehr man ändert/hinzufügt aber beim löschen wird nichts freigegeben.
Tatsächlich arbeite ich mit Move(); da viele Objecte (Kapitel und anderes) verschoben werden kann. Sogar ausschneiden und wo anderes einfügen ist möglich.
Wenn ich also Move() benutzte muss ich selber aufräumen?
Ebenso das umwandeln von Hex nach TBytes und zurück. Hatte diese Umwandlungen von diversen Webseiten mir abgeschaut.
Deine 4 Funktionen sind sicher besser und ich kann die ja nehmen.
Also keine doppelte Datenhaltung, dafür lieber immer bissl rechnen.
Wegen dem Constructor und destructor:
Wenn da nichts drin steht ausser inherited dann gleich weglassen.
Ich hatte bei meinem Programm beobachtet das es immer mehr Speicher will je mehr man ändert/hinzufügt aber beim löschen wird nichts freigegeben.
Tatsächlich arbeite ich mit Move(); da viele Objecte (Kapitel und anderes) verschoben werden kann. Sogar ausschneiden und wo anderes einfügen ist möglich.
Wenn ich also Move() benutzte muss ich selber aufräumen?
-
- Beiträge: 2118
- Registriert: Di 23. Sep 2014, 17:46
- OS, Lazarus, FPC: Win10 | Linux
- CPU-Target: x86_64
Re: Variable als Integer und als String(oder Binär <> Hex)
Hab grade gesehen es gibt auch HexToBin und BinToHex die praktisch genau das machen was meine funktionen machen, bis auf das alloziieren des Buffers.hubblec4 hat geschrieben:Das mit dem Integer und String ist völlig klar nun, Danke.
Ebenso das umwandeln von Hex nach TBytes und zurück. Hatte diese Umwandlungen von diversen Webseiten mir abgeschaut.
Deine 4 Funktionen sind sicher besser und ich kann die ja nehmen.
Genau, wenn die Responsetime zu lang wird, kannst du immernoch drüber nachdenkenhubblec4 hat geschrieben:Also keine doppelte Datenhaltung, dafür lieber immer bissl rechnen.
Klassen, new und GetMem müssen per hand freigegeben werden, Strings und Arrays sind Referenzgezählt, da macht der Compiler das ganz von selbsthubblec4 hat geschrieben:Ich hatte bei meinem Programm beobachtet das es immer mehr Speicher will je mehr man ändert/hinzufügt aber beim löschen wird nichts freigegeben.
Wenn du auf den daten movest dann ist das kein problem, Problematisch ists nur wenn du den Pointer movest. Z.B.hubblec4 hat geschrieben:Tatsächlich arbeite ich mit Move(); da viele Objecte (Kapitel und anderes) verschoben werden kann. Sogar ausschneiden und wo anderes einfügen ist möglich.
Wenn ich also Move() benutzte muss ich selber aufräumen?
Code: Alles auswählen
type TTestRec = record
Str: String;
end;
...
var r1, r2: TTestRec;
...
Move(r1, r2, sizeOf(TTestRec);
Was man machen kann ist sowas
Code: Alles auswählen
type TTestRec = record
Str: String;
end;
...
var r1, r2: TTestRec;
...
Move(r1, r2, sizeOf(TTestRec);
FillChar(r1, SizeOf(TTestRec), #00);
Code: Alles auswählen
type TTestRec = record
Str: String;
end;
...
var r1, r2: TTestRec;
...
r2 := r1;
Code: Alles auswählen
type TTestRec = record
Str: String;
end;
...
var r1, r2: TTestRec;
...
r2 := r1;
SetLength(r2.Str, r2.Str.Length);
Für das direkte Kopieren kannst du aber auch einfach Copy nehmen(was du ja schon benutzt). Der SetLength trick ist vor allem für Felder eines Records brauchbar.
Was hingegen kein problem ist ist sowas:
Code: Alles auswählen
var s1, s2: String;
...
SetLength(s2, s1.Length div 2);
Move(s1[1], s2[1], s1.Length div 2);
Alles was ich oben zu Strings geschrieben hab gilt übrigens auch für dyn arrays
Re: Variable als Integer und als String(oder Binär <> Hex)
HexToBin und BinToHex kenne ich auch schon und nutzte das auch.
Was das Move() angeht, denke ich habe ich dich falsch verstanden. Ich nutze Move was direkt an einer Klasse sitzt. Zum beispiel bei einer TObjectList gibt es .Move(old,new) ich denke das ist nicht das gleiche wie die eigenständige Move() procedure.
Für das Kopieren mit dem SetLenght hatte ich erst vor kurzem gelesen.
Klassen gebe ich immer selbstständig frei, hatte das so gelesen. Dennoch hatte sich der Speicherbedarf danach nicht reduziert.
Hatte dann ein anderes Programm geschrieben und dort im destrctor immer alles "geleert" und dadurch wurde dann auch immer wieder Speicher frei.
Daher ging ich davon aus man muss sich darum selbst kümmern.
Hast mir auf jedenfall schon wieder viel geholfen.
Was das Move() angeht, denke ich habe ich dich falsch verstanden. Ich nutze Move was direkt an einer Klasse sitzt. Zum beispiel bei einer TObjectList gibt es .Move(old,new) ich denke das ist nicht das gleiche wie die eigenständige Move() procedure.
Für das Kopieren mit dem SetLenght hatte ich erst vor kurzem gelesen.
Klassen gebe ich immer selbstständig frei, hatte das so gelesen. Dennoch hatte sich der Speicherbedarf danach nicht reduziert.
Hatte dann ein anderes Programm geschrieben und dort im destrctor immer alles "geleert" und dadurch wurde dann auch immer wieder Speicher frei.
Daher ging ich davon aus man muss sich darum selbst kümmern.
Hast mir auf jedenfall schon wieder viel geholfen.