Seite 1 von 1

Wie Datenstrukturen in PB umsetzen

Verfasst: 06.12.2013 18:24
von hoerbie
Hallo,

ich programmiere seit fast 30 Jahren, komme aber nun vom GFA Basic (ursprünglich mal Atari, dann bis heute Win-16-Bit, und weniges unter Win-32-Bit) neu zu PB, und brauche mal ein paar Tips bzw. habe ein paar Fragen, wie ich meinen bestehenden GFA-Code am besten in PB übersetze.

Da die alten GFA-Versionen recht problematisch waren, wenn es um Zeiger, Speicherbereiche, Strukturen etc. ging, es im Gegenzug unter GFA aber keine Probleme mit Strings gab, wenn diese CHR(0) enthielten, man also in Strings auch gut Word, Long etc. speichern konnte, und es im GFA tolle Funktionen zum entfernen einzelner Array-Elemente und einfügen von Array-Elementen an bestimmten Stellen im Array gab, habe ich dort zur Speicherung meiner Daten intensiv mit String-Arrays gerarbeitet, die mir quasi so etwas wie Strukturen nachgebildet haben, allerdings auch nicht so fix in der Länge waren, wie Strukturen.

Mir stellt sich nun die Frage, wie ich das folgende knapp gehaltene Beispiel sinnvoll in PB machen kann, um möglichst viel durch ein automatisches Code-Umschreibe-Tool zu erwischen und nicht zigtausend Codezeilen von Hand ändern zu müssen.

Z.B. habe ich ein String-Array in dem zwei unterschiedliche Datenarten abgelegt werden.
  • Jedes Array-Element ist entweder eine Kopfzeile oder eine Datenzeile, die ersten beiden Bytes sind ein Word-Wert, der einfach den Typ der im selben Element nachfolgenden Daten definiert (0=Kopfzeile, 1=Datenzeile).
  • Ein Kopfzeilen-Element enthält nach der Typfestlegung in den nächsten Bytes mehrere Byte, Word- oder Long-Werte, die einfach mit ihren jeweils 1, 2 oder 4 Byte Länge hintereinander in den String geschrieben werden, das Kopfzeilen-Element hat auch eine feste Länge
  • Ein Datenzeilen-Element enthält nach der Typfestlegung dann in den nächsten Bytes völlig andere Byte, Word- oder Long-Werte, und ausgehend von diesen Werten hat es eine Mindestlänge an Informationen, die Länge kann aber auch basierend auf bereits weiter vorne stehenden Werten ansteigen, um weitere zugehörige Werte im selben Element unterzubringen
In PB vereinfacht umgesetzt könnte das folgendermaßen aussehen:

Code: Alles auswählen

Structure kopf
  bnr.l
  std.a
  min.a
  knr.u
EndStructure

Structure daten
  anz.u
  stk.u

  anr.l
  bva.u
    apr.l
    bvp.u
      ltx.u
      txt.s
EndStructure

Structure zeile
  ein.w
  StructureUnion
    i.kopf
    a.daten
  EndStructureUnion
EndStructure
Die Struktur "kopf" ist soweit klar, in der Struktur "daten" sind in meiner bisherigen GFA-Konstruktion aber nur die ersten 4 Variablen "anz bis bva" fest, und abhängig vom Wert von "bva" folgen dann "apr und bvp" oder/und "ltx und txt". Soweit wäre das auch noch zu regeln, wenn ich einfach alle Variablen immer in der Struktur hätte und txt (das ist der einzige echte Text-String) auf eine feste Länge setzen würde. Es gäbe halt nur einen gewissen Overhead für die nicht immer gebrauchten Daten, was im Vergleich zu Anfang/Mitte der 90er, wo mein Code teilweise schon entstanden ist, bei heutigem Arbeitsspeicher kein Problem mehr wäre.

Schwieriger wird es nun, weil "anz" die Anzahl der von "anr bis ggfls. txt" folgenden Blöcke definiert, d.h. hinter dem ersten "txt" kann es in meinem GFA-String nun wieder neu losgehen mit Variablen ab "anr". Sicherlich wäre auch das mit deutlichem Overhead zu lösen, indem ich den Block "anr bis txt" in eine neue Struktur packe und diesen in "daten" wiederum als array einbaue.

Bleibt die ernsthafte Frage, ob das nicht irgendwie geschickter geht?

Eine Alternative und vermutlich schneller portierbar wäre mit Sicherheit, ein Array oder eine Liste nur mit Pointern auf einen je Zeile passend allozierten Speicherbereich aufzubauen. Dann könnte ich die für mein "im String speichern und da wieder rausholen" verwendeten GFA-Funktionen MKI$, MKL$ und CVI, CVL etc. einfach auf Speicherzugriff umschreiben.

Nur wie schnell und stabil ist PB dann, wenn man da einige 100 bis wenige 1000 kleine Speicherbereiche alloziert hat, und sich für jeden einzelnen den Pointer merken muß?

Ich hab zwar vor zig Jahren mal mit Pascal angefangen, auch mal C(++) gelernt, aber ich muß ehrlich sagen, daß mir damals die verketteten Listen, Pointer und der ganze Kram irgendwie nie so aufgegangen sind, ähnlich wie OOP nicht so mein Ding ist, auch wenn ich dadurch viele Dinge mit Sicherheit auf Umwegen lösen mußte.

Wie würde ein PB-Profi das lösen, lieber sauber mit Strukturen, oder mit Speicherbereichen?

So, fürs erste Posting ist das hier nun reichlich lang geworden, ich hoffe trotzdem auf Hilfe.

Im Voraus vielen Dank und vieleGrüße,
Jens

Re: Wie Datenstrukturen in PB umsetzen

Verfasst: 06.12.2013 18:53
von ts-soft
Ich würde sagen, Du beschäftigst Dich erstmal mit Listen, Maps und Arrays, auch in Strukturen.
Für Deine Daten wirst Du dann auch eine schnelle Lösung (ohne Pointer) finden, die nicht mehr
so kompliziert ist, wie Deine GFA-Umsetzung, die ich trotz Deiner langen Erklärung nicht verstehe :wink:

Gruß
Thomas

Re: Wie Datenstrukturen in PB umsetzen

Verfasst: 06.12.2013 19:03
von Derren
Das ganze "anz" und "anr" verwirrt mich ein bißchen.

Nochmal zusammenfassend. Du hast eine Datei in der auf einander folgend Bytes und Words un Longs stehen, ja?
Erste Frage: Wenn ein Word den Beginn eines Elements anzeigt und entweder 0 oder 1 ist, dann kann es logischerweise keine Words mit 0 oder 1 in den Datensätzen geben, oder?
Zweitens: Ist der Datensatz strukturiert oder woher weißt du dass du z.B. ein Long auslesen musst und nicht 2 Bytes und ein Word? Was bedeutet denn "variable Länge". Hast du da eine Fixe Länge, die einfach nur vervielfacht wird?
Ich verstehe nämlich nicht, wie du einen Datensatz mit 10 Bytes haben kannst und auch einen mit 15 Bytes z.B.

Machen wir mal ein Beispiel.
Du hast einen Datensatz der so aussieht:

Code: Alles auswählen

0000 FF   AB57 2563 FF99AA77
Kopf Byte Word Word Long = fixe Länge von 9 Bytes plus Word Identifier

0001 1001 03  4645 1024  12568940 6868 3085  56FB14A9 1453 A845  B400976C
Kopf UID  cnt item price info	  item price info     item price info
Jetzt hast du also erst einen Identifier für den Arrayeintrag und dann einen Counter, der dir sagt, wie viele Unterelemente in dem Array sind. Die Unterelemente habe alle die gleiche Länge und sind identisch aufgebaut. Natürlich kann es verschiedene Typen von Unterelementen geben, dann brauchst du halt nur einen weiteren Identifier.


Jetzt liest du also den kompletten Datensatz mit "ReadData()" in einen Puffer. Dann iterierst du durch den Buffer bis zu einem Word "0000" kommst und dann weiter bis zu "0001" kommst. Alles dazwischen wird dann in ein entsprechend strukturiertes Array geschrieben.

Code: Alles auswählen

Structure Dateninfo
  item.b
  price.b
  info.l
EndStructure

Structure Datensatz
  kopfVar1.b
  kopfVar2.w
  kopfVar3.w
  kopfVar4.l

  bodyUID.b
  Dim Info.DatenInfo(cnt)
EndStructure

Dim Daten.Struktur(0)

Debug Daten(0)\kopfVar1 ;FF   
Debug Daten(0)\kopfVar2 ;AB57 
Debug Daten(0)\kopfVar4 ;FF99AA77
Debug Daten(0)\DatenInfo(1)\price ;3085  


Re: Wie Datenstrukturen in PB umsetzen

Verfasst: 06.12.2013 20:26
von hoerbie
Hallo,

erstmal vielen Dank dafür, meinen Text verstehen zu wollen.

Mir geht es in erster Linie um die Haltung im Speicher und den (schnellen) Zugriff darauf, Änderungen daran etc. Allerdings ist es richtig erkannt, daß ich diese Strings nicht nur als Datenstruktur im Ram nutze, sondern auch mehr oder weniger so in eine Datei speichere und wieder aus dieser einlese.

Generell ist alles schon strukturiert bzw. entspricht einem bestimmten festgelegten Aufbau, der sich halt nur abhängig von bestimmten Werten im weiteren Verlauf desselben "Strings" in festgelegter Weise verändern kann.

Im Prinzip nutze ich derzeit jedes einzelne Array-Element (also einen aus Bytes, Words und Longs strukturiert zusammengesetzten String) wie einen einfachen Speicherbereich, nur daß ich eben keinen richtigen Pointer brauche.

Mal ein Beispiel in Bytes, wie es derzeit im String aussieht, und wie es auch in einem Speicherbereich aussehen könnte (und so ähnlich stehen ja auch die Daten innerhalb einer Struktur im Speicher:

Eine Kopfzeile:

Code: Alles auswählen

---ein---  -------bnr---------  -std--  -min--  ---knr---
--Word---  -------Long--------  -Byte-  -Byte-  --uWord--
0          15                   17      24      258
Byte Byte  Byte Byte Byte Byte  Byte    Byte    Byte Byte
0    0     15   0    0    0     17      24      2    1
Eine kurze Datenzeile, da anz=1 und bva=0:

Code: Alles auswählen

---ein---  ---anz---  ---stk---  -------anr---------  ---bva---
--Word---  --uWord--  --uWord--  -------Long--------  --uWord--
1          1          3          523                  0
Byte-Byte  Byte-Byte  Byte-Byte  Byte-Byte-Byte-Byte  Byte-Byte
1    0     1    0     3    0     11   2    0    0     0    0
Eine längere Datenzeile, da bva!=0:

Code: Alles auswählen

---ein---  ---anz---  ---stk---  -------anr---------  ---bva---  -------apr---------  ---bvp---
--Word---  --uWord--  --uWord--  -------Long--------  --uWord--  -------Long--------  --uWord--
1          1          3          523                  8          990                  0
Byte-Byte  Byte-Byte  Byte-Byte  Byte-Byte-Byte-Byte  Byte-Byte  Byte-Byte-Byte-Byte  Byte-Byte
1    0     1    0     3    0     11   2    0    0     8    0     222   3    0    0    0    0
Eine längere Datenzeile, wo es zwei Blöcke anr+bva gibt, weil anz=2

Code: Alles auswählen

---ein---  ---anz---  ---stk---  -------anr---------  ---bva---  -------anr---------  ---bva---
--Word---  --uWord--  --uWord--  -------Long--------  --uWord--  -------Long--------  --uWord--
1          1          3          523                  0          522                  0
Byte-Byte  Byte-Byte  Byte-Byte  Byte-Byte-Byte-Byte  Byte-Byte  Byte-Byte-Byte-Byte  Byte-Byte
1    0     2    0     3    0     11   2    0    0     0    0     10   2    0    0     0    0
Ich greife dann halt in GFA mit CVI, CVL etc. ähnlich darauf zu, wie man es in PB auf den Speicherbereich mit PeekW(*Startpointer) PeekL(*Startpointer+2) etc. machen würde.
D.h. ich lese jeden String von vorne, lese also erst den Wert in "ein", und weiß dann, es folgt Kopfzeile oder Datenzeile.
Wenn Kopfzeile finde ich dann dahinter den Long-Wert "bnr", anschließend zwei Byte-Werte "std" und "min" und abschließend ein unsignedWord "knr".
Wenn Datenzeile lese ich die unsignedWord Werte "anz" und "stk" ein, und weiß dann, wie oft ich nachfolgend immer den Long-Wert "anr" und den unsignedWord-Wert "bva" finde. Wenn "bva" ungleich 0 ist, folgt halt unter Umständen direkt nach dem "bva" noch z.B. Long "apr" und Word "bvp", bevor dann wieder ein "anr" kommen kann.
D.h. ich brauche da keine Marker oder ähnliches, die Art der folgenden Daten wird immer anhand der im selben String vorher stehenden Daten festgelegt.

Ich hoffe, es ist jetzt verständlicher geworden, und mir kann jemand einen Tip geben, wie ich das in PB am besten regeln kann.

Gruß, Jens

Re: Wie Datenstrukturen in PB umsetzen

Verfasst: 06.12.2013 20:43
von ts-soft
Du benötigst also unbedingt diese Datenstrukture, die sich auch nur Sequentiell lesen läßt?
Zum Speichern als Datei vielleicht sinnvoll, aber so würde ich es nicht im Programm-Speicher
halten, der Zugriff ist doch viel zu langsam.

Irgendwie kann ich mich an diese 80er Anordnung nicht mehr reindenken :mrgreen:

Wenn das Dateiformat nicht unbedingt kompatible zum bisherigem sein muß, kann man das
sicher einfacher und schneller machen, evtl. auch eine DB zur Speicherung nutzen oder xml.

Gruß
Thomas

Re: Wie Datenstrukturen in PB umsetzen

Verfasst: 06.12.2013 22:14
von hoerbie
Hallo Thomas,

unbedingt mit Sicherheit nicht, ich geb ja zu, daß so ein Speicher-sparen bei GB-Rams unnötig ist, und auch einiges an Performance kostet.

Es geht aber bei dem gesamten Programm um reichlich Code-Zeilen, die ich gerne in einem ersten Schritt möglichst einfach konvertiert hätte, statt die - zugegeben überholten - alten Datenstrukturen nun schon alle neu umsetzen zu müssen, denn das käme mit dem dann notwendigen Testing einer Neuentwicklung gleich. Irgendwann werde ich da nicht drum rumkommen, mein erster Schritt sollte aber an sich erstmal die Portierung nach PB sein, um eine zuverlässige Basis zu haben, die nicht die immer seltener werdenden 32Bit-Windows benötigt.

Der generelle Gedanke, es mit verschachtelten Strukturen und Array/Liste einer Struktur in einer anderen Struktur oder gar einer StructuredUnion zu machen, scheint auch so nicht zu gehen, da hagelt es dann Fehlermeldungen.

Gruß, Jens

Re: Wie Datenstrukturen in PB umsetzen

Verfasst: 06.12.2013 22:19
von Derren
Dein Beispiel macht Sinn, bis auf den Teil wo der "apr" Block bei "anz=2" fehlt.
Ansonsten passt doch alles und du kannst die von mir gepostete Beispielstruktur anpassen.

Es geht doch hier darum ein Programm in PB zu schreiben, dass mit den alten txt-Dateien umgehen kann, oder? Und nicht darum ein PB Programm zu schreiben, dass möglichst genauso wie das alte Programm funktioniert (mit Pointern und direkter Speichermanipulation).

In sofern kannst du doch Arrays und Listen problemes nutzen. Natürlich auch um wieder in dein txt-Dateiformat zu speichern. Sollte doch relativ einfach sein. Dann, wann immer dir danach ist kannst du einfach die Lese- und Speicherfunktionen abändern zu XML, z.B. Dann hast du einen einfachen Konverter von einem Dateiformat ins andere.

Re: Wie Datenstrukturen in PB umsetzen

Verfasst: 06.12.2013 22:36
von ts-soft
So wie Derren es beschrieben hat, meinte ich es auch. Eine Speicher und Ladefunktion, die Dein
Format schreibt, aber im RAM werden eben etwas "modernere" Formate genutzt, die auch einen
schnelleren und vor allem auch einen direkten Zugriff erlauben.

Abgesehen von der Idee und Aufgabe, wirst Du den GFA-Source kaum nutzen können, dafür sind die
Sprachen zu unterschiedlich, also eine Neuprogrammierung, auf Basis des vorhandenen, wird unver-
meidlich sein.

Re: Wie Datenstrukturen in PB umsetzen

Verfasst: 09.12.2013 14:40
von hoerbie
Hallo,

danke Euch, vor allem für das ins Spiel bringen von Datenbanken, das hat mir einige Ideen gebracht!

Ich denke mal, ich werde die Datenhaltung im Ram am besten durch mehrere Arrays/Listen/Maps lösen, die jeweils nur durch eine klare Struktur definiert sind, und sie dann, so wie man es auch z.B. in MySql macht, einfach per (Zeilen-) IDs verknüpfen, also die Kopfdaten in ein Array, und die eigentlichen Daten verteilen auf ein weiteres Array mit den je Datenzeile nur einmal benötigten Daten, und dann die "schleifenmäßig" auftretenden in noch ein weiteres Array.

Ansonsten hab ich hier oder/und im englischen Forum auch noch einiges gefunden, daß sich wohl in fixen Strings durchaus CHR(0) Bytes unterbringen lassen, man dann nur nicht mit den vorhandenen PB-Funktionen über das erste CHR(0) hinauskommt, ich also ggfls. nur noch mit eigenen Routinen per Pointer Zugriff bekäme. Bisherige eigene Versuche in diese Richtung waren zumindest ganz gut. Mal sehen, was ich da noch so mache, im Moment teste ich mich erstmal Stück für Stück durch weitere potentielle Problemstellen.

Mit dem Quellcode von GFA nach PB, nun, ich habe noch die Hoffnung, einen Großteil der notwendigen Änderungen mit einem selbst geschriebenen Tool erledigen zu können, so viele Unterschiede gibt es da gar nicht mehr, wenn ich mir selbst noch ein paar Funktionen dazu schreibe.

Gruß, Jens

Re: Wie Datenstrukturen in PB umsetzen

Verfasst: 09.12.2013 16:33
von Derren
Verstehe nicht warum du bei einer fixen Struktur mit den PB Stringbefehlen arbeiten willst.
Erst musst du die Struktur aufschlüsseln und dann kannst du die Stringbefehle auf vorhandene Strings anwenden. Und wenn dein String dann immernoch aus welchen Gründen auch immer Chr(0) beinhalten sollte kannst du es auch mit einer einfachen Funktion durch ein anderes neutrales Zeichen ersetzen.