Autor Beitrag
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Do 28.05.09 14:20 
Moin!

user profile iconGammatester hat folgendes geschrieben Zum zitierten Posting springen:
Jetzt muß es halt das aller-allerletze Mal sein (das ist beliebig iterationsfähig, also bitte keine weiteren guten Ratschläge).
Hey, das erinnert mich an Terry Pratchett, Trolle und Zählen: 1, 2, 3, Viele, Viele-1, Viele-2, Viele-3, Viele-Viele, ... :lol:

user profile iconGammatester hat folgendes geschrieben Zum zitierten Posting springen:
Ich sehe nirgends ein @
Ja, das ist korrekt, ich wollte es vereinfachen. :nixweiss:

user profile iconGammatester hat folgendes geschrieben Zum zitierten Posting springen:
Die diskutierte Situation ist
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
var
    Int: Integer;
    Float: Double;
type
  PDouble = ^Double;
begin
  PDouble(@int)^ := Float;
Nein, ist sie nicht, denn der generierte Pointer zeigt bei dir auf einen einfachen Datentyp (und das auch noch auf dem Stack), bei mir immer auf den Anfang eines dynamischen Strings. Da ein Heap-Block aber immer min. 16 Bytes groß ist, ich aber nur einfache Datentypen typkonform gecastet so "verwerflich" da rein schreibe, kann es prinzipiell nicht zu einem Problem kommen - selbst wenn die Typlänge nicht passen sollte (was ich durch Vermeidung von generischen Typen ausgeschlossen haben sollte). :idea:

//EDIT: ---------- (hatte jetzt erst Zeit, um ausführlicher auf die "diskutierte Situation" einzugehen)

Zunächst mal hast du Recht, wenn du sagst, dass ich beim Verzicht auf generische Typen auch kein Integer verwenden darf. Ja, der Punkt geht voll auf mein Sündenkonto (ich bin ketzerischer Weise davon ausgegangen, dass die Sprache Delphi es nicht mehr erleben wird, dass Integers 64 Bit breit sind). Ich bereue und werde deshalb im Folgenden Longint dafür verwenden. :flehan:

Kommen wir zur Analyse der wirklich diskutierten Version(en):
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
// mein Vorschlag
SetLength(BinMsg,4); // SizeOf(Longint)=4, Basistyp der Pseudo-Unit System, Wert ist garantiert
PLongint(@BinMsg[1])^ := MyLongint; // Daten schreiben

// dein Vorschlag
SetLength(BinMsg,sizeof(MyLongint)); // dynamische Mengenangabe
move(@BinMsg[1], MyLongint, sizeof(MyLongint)); // Kopierschleife auf Basis der dynamischen Mengenangabe
Abstrahieren wir mal das, was da im Prinzip passiert:
  • Speicherplatz reservieren
    mein Ansatz: garantierte Basistypmenge (Konstante laut Doku)
    dein Ansatz: dynamisch ermittelte Größe von Basistypen entsprechen immer der Basistypgröße (ersetzt der Compiler durch eine Konstante)
    Fazit: gleichwertig
  • Pointer generieren
    mein Ansatz = dein Ansatz, identisch -> @BinMsg[1]
    Fazit: gleichwertig
  • Daten schreiben
    mein Ansatz: Pointer-Typecast auf einen Basistyp, einfache Schreiboperation der CPU
    dein Ansatz: Kopierschleife, gesteuert durch eine vom Compiler eingesetzt Konstante für die Basistypgröße
    Fazit: mein Ansatz ist performanter, da die CPU das durch eine native Operation abwickeln kann, dein Ansatz ist eine Schleife, Aufwand: O(1) < O(n)
  • Ergebnis aus Sicht deines Ansatzes: gleichwertig - gleichwertig - höherer Aufwand :|
Abschließend noch etwas zu dem von dir angepassten Beispiel:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
// mein Ansatz aus deiner Sicht
  var
    Int: Integer;
    Float: Double;
begin
  PDouble(@Int)^ := Float; // hier wird Speicher überschrieben

// jetzt mal das Gleiche ala deinem Vorschlag per move():
  var
    Int: Integer;
    Float: Double;
begin
  move(@Int, Float, SizeOf(Float)); // hier wird Speicher überschrieben
Das sollte das von dir modifizierte Beispiel ad absurdum führen, da deine Version genau so zielsicher Speicher überschreibt, wie meine. Ich wollte mit dem Beispiel ursprünglich zeigen, dass der Compiler bei einem Pointer-Typecast sehr wohl die Schreiboperation typensicher ausführt. Dass der referenzierte Pointer natürlich keiner Typprüfung unterliegt, ist ja wohl klar (oder: der Sinn der Sache). Deshalb muss ich die Unterstellung, ich wolle absichtlich etwas falsch verstehen, an dieser Stelle klar an dich zurückgeben!

Gesamtfazit: Unsere Ansätze sind funktional gleichwertig, meiner ist aber performanter. Wie du also darauf kommst, dass dein Ansatz prinzipiell "besser" sein soll, ist mir nicht klar. "Universeller einsetzbar" im Austausch gegen "besser" fände ich angemessen. ;)

Dass das ganz konkret auf mein Tutorial bezogen "keine gute Idee" ist (OK, das habe ich in dem betreffenden Beitrag leider nicht dazu geschrieben, allgemein ist diese Aussage sicher nicht korrekt - hier scheint unser Hauptmissverständnis zu liegen; sorry also dafür), hat zwei Gründe:
  • keine generischen Typen, da der FrameAssembler TCmdSeq (das ist nämlich die Stelle im Tut, um die es hier wirklich geht) vorhersagbare Framegrößen erzeugen soll (by-design)
  • dein Ansatz, Basistypen per move() zu verarbeiten, mir (im Sinne des Tuts) zu nahe legt, das ganze auch mit Verbunddatenstrukturen zu tun, womit die FrameAssembler-Klasse ihre Allgemeingültigkeit verliert, weil sie zu stark ausdifferenziert
cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.