![]() |
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? |
AW: kleine Datentypen (BYTE) zusammenfassend als z.B. WORD/Integer übergeben
Für 2 Word zu einem Integer gibt es
![]() 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. ![]() Oder den ![]() z.B. bei Single/Double/Extended kann man via
Delphi-Quellcode:
lesend und schreibend auf die Eintelteile zugreifen.
MySingleVar.Bytes[0]
|
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:
Einen solchen Record kann man dann auch noch mit ein paar Methoden schmücken:
type
TCombinedCoord = packed record var integer of // <= das belegt keinen Speicher 0: (AsWord: Word); 1: (x, y: Byte); end;
Delphi-Quellcode:
So dass man z.B. folgendes schreiben könnte:
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;
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));
|
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- |
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 |
AW: kleine Datentypen (BYTE) zusammenfassend als z.B. WORD/Integer übergeben
Delphi-Quellcode:
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)
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)); |
AW: kleine Datentypen (BYTE) zusammenfassend als z.B. WORD/Integer übergeben
Zitat:
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:
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. |
AW: kleine Datentypen (BYTE) zusammenfassend als z.B. WORD/Integer übergeben
Zitat:
Doch, dafür gibt es ![]() |
AW: kleine Datentypen (BYTE) zusammenfassend als z.B. WORD/Integer übergeben
Zitat:
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:
CASE OF Dawzischen steht ein Typ, für die Zuordnung der CASES, welches auch eine "Variable" sein kann.
Delphi-Quellcode:
Das nennt sich Variante-Records, also wo quasi verschiedene "Varianten" der Speicherbenennug übereinander liegen.
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: ( ... ); 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. |
AW: kleine Datentypen (BYTE) zusammenfassend als z.B. WORD/Integer übergeben
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:25 Uhr. |
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