Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   kleine Datentypen (BYTE) zusammenfassend als z.B. WORD/Integer übergeben (https://www.delphipraxis.net/216017-kleine-datentypen-byte-zusammenfassend-als-z-b-word-integer-uebergeben.html)

Amicello 14. Okt 2024 15:07

kleine Datentypen (BYTE) zusammenfassend als z.B. WORD/Integer übergeben
 
Hallo...

ich suche nach einem eleganten Weg - vielleicht kann hier jemand weiterhelfen.
Ich versuche das mal irgendwie verständlich zu erklären.

Beispielsituation:
Es gibt 2 Parameter als kleine Dateitypen - z.B. x/y Koordinatenpaare als Byte (0..255)

Theoretisch könne man diese zu einem 16-bit Word zusammensetzen - und praktischerweise
als eine einzige Variable benutzen um sie Funktionen zu übergeben und/auch als Erbegnis zu erhalten.


So in der Art:

Code:
Function       Mittelpunkt(coord1,coord2:TCombinedCoord):TCombinedCoord;
        begin   result.x := (coord1.x + coord2.x) shr 1;
                result.y := (coord1.y + coord2.y) shr 1;
        end;

Sprich die Funktion bekommt nur zwei WORD's geliefert, rechnet aber mit dem Byte-Anteilen,
und liefert dann ein kombiniertes WORD des Koordinatenpaares zurück.


Verwenden würde ich das dann am liebsten so:

Code:
MeinMittelpunkt := Mittelpunkt( startpunkt, endpunkt );
MeinMittelpunkt := Mittelpunkt( (x1,y1), (x2,y2) );
MeinMittelpunkt := Mittelpunkt( (14,52), (29,151) ); // wäre toll, wenn das so geht


Str := 'Mittlere x-Koordinate: ' + i2s(MeinMittelpunkt.x);

Ich hoffe das war so im Groben verstöndlich.
Kann man da mit packet record o.ä. etwas Elegantes tricksen?

himitsu 14. Okt 2024 15:25

AW: kleine Datentypen (BYTE) zusammenfassend als z.B. WORD/Integer übergeben
 
Für 2 Word zu einem Integer gibt es Delphi-Referenz durchsuchenMakeLong, bzw. MakeULong ... und zurück via HiWord und LoWord.

Oder man nimmt Records,
entweder zum Speichern (noch ein paar ImpliciteCasts und 'nen Constructor dran und die lassen sich super nutzen)
oder zum Casten, wie z.B. Delphi-Referenz durchsuchenWordRec.

Oder den Delphi-Referenz durchsuchenTWordHelper am Word-Typen, aber leider fehlen bei den Delphi-Helper für Byte/Word/usw. die nötigen ZugriffsProperty.
z.B. bei Single/Double/Extended kann man via
Delphi-Quellcode:
MySingleVar.Bytes[0]
lesend und schreibend auf die Eintelteile zugreifen.

dummzeuch 14. Okt 2024 17:02

AW: kleine Datentypen (BYTE) zusammenfassend als z.B. WORD/Integer übergeben
 
Was willst Du damit erreichen? Speicher sparen? Klar geht das, aber bei vielen Werten geht das dann ziemlich auf die Performance und nicht zuletzt auf die Lesbarkeit / Debugbarkeit.

Ich würde dann vermutlich ein
Delphi-Quellcode:
type
  TCombinedCoord = packed record
  var integer of // <= das belegt keinen Speicher
    0: (AsWord: Word);
    1: (x, y: Byte);
  end;
Einen solchen Record kann man dann auch noch mit ein paar Methoden schmücken:
Delphi-Quellcode:
type
  TCombinedCoord = packed record
    // Methoden müssen vor dem VAR-Part deklariert werden
    class function From(_x, _y: byte): TCombinedCoord; static;
  var integer of
    0: (AsWord: Word);
    1: (x, y: Byte);
  end;
So dass man z.B. folgendes schreiben könnte:

Delphi-Quellcode:
MeinMittelpunkt := Mittelpunkt(TCombinedRecord.From(x1,y1), TCombinedRecord.From(x2,y2));

Ob das aber soviel besser ist?

Lesbarer wäre definitiv eine normale Funktion statt einer Methode:

Delphi-Quellcode:
MeinMittelpunkt := Mittelpunkt(Combine(x1,y1), Combine(x2,y2));

himitsu 14. Okt 2024 17:38

AW: kleine Datentypen (BYTE) zusammenfassend als z.B. WORD/Integer übergeben
 
Ach ja, da es X/Y-Koordinaten sind, würde ich, falls ich einen Record nutze, eher versuchen etwas Vorhandenes zu verwenden, also z.B.
TSmallPoint (2*SmallInt)
TPoint (2*LongInt)
TPointL (2*Longint)
TPointfx (Word+SmallInt)
TPointFloat (2*Single)
TPair<Byte,Byte>
...


Aber normal werwende ich sowas nur, wenn ich Daten in/durch eine bestehende Struktur quetschen muß.
z.B. bei Memos und ScrollBars, wo Anfang+Ende oder X/Y-CursorPos als "ein" LPARAM ins SendMessage rein muß. (siehe MakeLong)

Oder wo ich eine Funktion hab, welche nicht überladen werden kann, aber unterschiedliche Typen bekommen soll.
In ältern Delphis z.b. für ein Named-Array, wo das Index-Property mit Index oder Name genutzt werden sollte, wo der Index-PropertyTyp also ein Record mit AutoCast war, welcher String und Integer als Parameter entgegennimmt.

Sonst versucht ich möglichst schon die Eingabe einfach zu machen und sowas mir zu ersparen-

Amicello 14. Okt 2024 18:44

AW: kleine Datentypen (BYTE) zusammenfassend als z.B. WORD/Integer übergeben
 
Da verneige ich mich doch gleich mal in Richtung Essen und Japan für die perfekten Antworten.
Nach einem schon existierenden TPoint/TPair zu suchen - auf so etwas Simples bin ich gar nicht gekommen.
Wieder was gelernt!

Bei Packed Records hat mich immer der "Integer of" Teil verwirrt:
Sprich wo liegt dieses Integer, wann wird es im Code abgefragt, ist das nicht unnötig und was bedeuten die Werte..
Dein "<= das belegt keinen Speicher" interpretiere ich jetzt mal so, dass man das einfach ignorieren kann -
weil Delphi das weder anlegt noch auswertet sondern "nur einfach so" geschrieben haben möchte. Richtig?


"Was willst Du damit erreichen?"
Immer zwei Variablen für x/y seperat zu übergeben fand ich umständlich.
Zu dem gehören die für mein Verständnis ja auch logisch zu einer Einheit.

Habt mir sehr weitergeholfen!

Merci

himitsu 14. Okt 2024 19:28

AW: kleine Datentypen (BYTE) zusammenfassend als z.B. WORD/Integer übergeben
 
Delphi-Quellcode:
MeinMittelpunkt := Mittelpunkt(MakeLong(x1,y1), MakeLong(x2,y2));

MeinMittelpunkt := Mittelpunkt(Point(x1,y1), Point(x2,y2));
MeinMittelpunkt := Mittelpunkt(TPoint.Create(x1,y1), TPoint.Create(x2,y2));
Wenn es nur ums Übergeben geht, dann ist MakeLong eher ungünstig, da die Werte beim Debuggen ja erst im Kopf wieder zerlegt werden müssen (Ansicht der Variable als HEX wäre einen Hauch hilfreich)

Medium 14. Okt 2024 21:59

AW: kleine Datentypen (BYTE) zusammenfassend als z.B. WORD/Integer übergeben
 
Zitat:

Zitat von Amicello (Beitrag 1542171)
Bei Packed Records hat mich immer der "Integer of" Teil verwirrt:

Da vermischt du zwei Dinge:
Packed Records sind eigentlich ganz normale Records. Üblicherweise werden die im Speicher (je nach eingestellter Compiler-Option, aber ich gehe von der Voreinstellung aus) an den Wort-Grenzen der gewählten Prozessorarchitektur ausgerichtet (aktuell also 32- oder 64-Bit Wortbreite). Heisst, dass selbst wenn du in einem Record nur ein Byte deklarierst, wird ein nachfolgendes Byte nicht ein Byte weiter im Speicher liegen, sondern ein DWORD oder QWORD weiter.
Wenn du nun einen Record als "packed" deklarierst, wirft der Compiler das über Bord, und das zweite Byte wird tatsächlich nur ein Byte später im Speicher stehen.
Grund ist, dass es üblicherweise schneller und effizienter ist, immer so auf den Speicher zuzugreifen, dass man sich immer an den "natürlichen" Grenzen der Architektur orientiert. Anderenfalls muss hinter den Kulissen immer etwas "gepflückt und geschubst" werden - entweder vom Compiler, oder die CPU macht das selber. Kostet aber halt immer Taktzyklen.
Daher sollte man einen Record nur dann packed deklarieren, wenn es essenziell wichtig ist, dass im Speicher nachher alle Felder des Records dicht an dicht liegen. Ein paar Bytes hier und da "sparen" rechtfertigt das heutzutage meiner Meinung nach nicht mehr.

Das andere sind "Variante Records":
Das ist eine etwas verwirrende Schreibweise, da Delphi sonst kein Vokabular hat, um unterschiedliche Namen für den selben Speicherbereich zu deklarieren. Du sagst hier am Ende nur: Es gibt ein Integer-langes Stück Speicher, und es folgt eine Liste von ebenfalls jeweils insgesamt Integer-langen deklarationen, unter dessen Namen man wahlweise auf diesen Bereich (oder Teilen von diesem) später zugreifen kann.
Die gezeigte Deklaration sagt also:
1) Es gibt ein Stück Speicher der Länge SizeOf(Integer) (was hier allerdings falsch wäre, es müsste "Word" benutzt werden!)
2) Du kannst das ganze Word unter dem Namen "AsWord" erreichen.
3) Du kannst alternativ das erste Byte desselben Words unter dem Namen "x", das andere "y" erreichen.


Zitat:

"Was willst Du damit erreichen?"
Immer zwei Variablen für x/y seperat zu übergeben fand ich umständlich.
Zu dem gehören die für mein Verständnis ja auch logisch zu einer Einheit.

Habt mir sehr weitergeholfen!
Dafür sind definitiv Records, oder besser noch Klassen da! Wenn es dir rein um die "Semantik" geht, sind das die Werkzeuge - sie wurden genau dafür entwickelt!
Rumgefummel an/in internen Strukturen kann - in sehr spezifischen Einzelfällen(!) - Sinn machen, aber das sollte dann seeeehr gut begründet und dokumentiert sein. Deine Motivation würde ich hier keinesfalls als "guten Grund" ansehen können, weil es wie gesagt High-Level Mechanismen gibt, die ganz genau dafür da sind, und Lesbarkeit, Testbarkeit und Debugbarkeit sogar erhöhen, statt quasi komplett zu zerstören.

jaenicke 14. Okt 2024 22:10

AW: kleine Datentypen (BYTE) zusammenfassend als z.B. WORD/Integer übergeben
 
Zitat:

Zitat von Medium (Beitrag 1542176)
Das ist eine etwas verwirrende Schreibweise, da Delphi sonst kein Vokabular hat, um unterschiedliche Namen für den selben Speicherbereich zu deklarieren.

Nur der Vollständigkeit halber, das hat damit sonst nichts zu tun:
Doch, dafür gibt es absolute.

himitsu 14. Okt 2024 22:40

AW: kleine Datentypen (BYTE) zusammenfassend als z.B. WORD/Integer übergeben
 
Zitat:

Zitat von Medium (Beitrag 1542176)
Packed Records sind eigentlich ganz normale Records. Üblicherweise werden die im Speicher (je nach eingestellter Compiler-Option, aber ich gehe von der Voreinstellung aus) an den Wort-Grenzen der gewählten Prozessorarchitektur ausgerichtet (aktuell also 32- oder 64-Bit Wortbreite). Heisst, dass selbst wenn du in einem Record nur ein Byte deklarierst, wird ein nachfolgendes Byte nicht ein Byte weiter im Speicher liegen, sondern ein DWORD oder QWORD weiter.

Jo, Packed-Records sind einfach nur Records mit {$ALIGN 1}
maximale Ausrichtung an 1 Byte-Grenze

Gleichgroße Typen folgen immer einander.
folgt ein größerer Typ, dann wird er an "seiner" Größe ausgerichtet, oder maximal so viel, wie vorgegeben.

Also normal wird ein Word an 2 Byte ausgerichtet,
mit einer Lücke, wenn davor nur 1 Byte war.

Packed-Records oder Records mit einer definierten Ausrichtung braucht man nur, wenn der Records prozessübergreifend gespeichert/übertragen wird.

Innerhalb des selben Prozesses, ist es "optimaler", wenn ordentlich ausgerichtet wird, damit möglichst effizient auf den Speicher zugegriffen werden kann,
außer, es geht um maximale Speicher-Ersparnis. (meistens ist Effzienz aber das Wichtigere)


Zitat:

Integer of
Hier ist eigentlich CASE das wichtige Wort.
CASE OF

Dawzischen steht ein Typ, für die Zuordnung der CASES, welches auch eine "Variable" sein kann.
Delphi-Quellcode:
case Boolean of
  True: ( ... );
  False: ( ... );

case Char of
  'A': ( ... );
  'B': ( ... );

case Integer of
  0: ( ... );
  1: ( ... );

case Was: Integer of
  0: ( ... );
  1: ( ... );

// das Vorhergehende entspricht quasi Diesem, also mit einer Variable, in der man speichern kann (nicht muß), welcher Teil gültig ist.
Was: Integer;
case Integer of
  0: ( ... );
  1: ( ... );
Das nennt sich Variante-Records, also wo quasi verschiedene "Varianten" der Speicherbenennug übereinander liegen.
Auch andere Sprachen (C++) kennen sowas.
PS: Der Typ Variant nutzt intern sowas, um z.B. einen Integer oder einen String/PChar auf der selben Stelle zu speichern.

Das einzige Problem für Delphi ist, dass dem CASE das eigene END fehlt
und deswegen im Delphi/Pascal der Variante Block ausschließlich am Ende des Records stehen kann.
In C++ kann er auch mittendrin sein, was eine Konvertierung von Code nicht erleichtert.

Medium 14. Okt 2024 22:41

AW: kleine Datentypen (BYTE) zusammenfassend als z.B. WORD/Integer übergeben
 
Zitat:

Zitat von jaenicke (Beitrag 1542177)
Zitat:

Zitat von Medium (Beitrag 1542176)
Das ist eine etwas verwirrende Schreibweise, da Delphi sonst kein Vokabular hat, um unterschiedliche Namen für den selben Speicherbereich zu deklarieren.

Nur der Vollständigkeit halber, das hat damit sonst nichts zu tun:
Doch, dafür gibt es absolute.

Ah okay, ich dachte das ist ein Spezialkonstrukt, dass nur in Siemens SCL existiert. Scheint aber nicht im Kontext von Record-Feldern zu gehen, vermutlich dann eher ein Relikt aus Turbo Pascal Zeiten oder?


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:25 Uhr.
Seite 1 von 2  1 2      

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-2025 by Thomas Breitkreuz