AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Codedesign

Ein Thema von Luckie · begonnen am 10. Nov 2003 · letzter Beitrag vom 6. Jan 2004
Antwort Antwort
Seite 6 von 6   « Erste     456   
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#51

Re: Codedesign

  Alt 14. Nov 2003, 05:10
Speziell an Hagen noch mal:

Du hast auf Seite 1 oder 2 folgende Aussagen gemacht:

in den Thread hats du folgende Aussagen getroffen:
  • 3 ordinale Paramter maximal für Proceduren
  • 2 ordinale Paramter maximal für Methoden (Self ist der 3. unsichtbare Parameter)
  • register Aufrufkonvention wenn möglich
  • Result immer nur am Ende der Funktion belegen, oder vor einem Exit;
  • möglichst wenige lokale unkomplizierte Variablen
  • das Aufsplitten komplexer Funktionen auf mehrere weniger komplexe Funktion macht den Code meistens schneller, da der Optimierer besser arbeiten kann (gilt auch für nested Proceduren)
Könntest du die mir bitte noch mal erleätern / begründen? Die Hintergründe hierzu wären nicht schlecht zu erfahren. Danke.
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Benutzerbild von Phoenix
Phoenix
(Moderator)

Registriert seit: 25. Jun 2002
Ort: Hausach
7.640 Beiträge
 
#52

Re: Codedesign

  Alt 14. Nov 2003, 08:14
Zitat von negaH:
6.) immer 2 Leerzeichen werden Blöcke eingerückt, nicht 3,4,5 oder 8 und schon garnicht Tabulatoren !! 2 Leerzeichen nichts anderes. Es kommt häufig vor das man einem PASCAL Source in anderen Editoren betrachten und Tabulatoren zerstören die Formatierungen.
Da muss ich Dir deutlichst(!) widersprechen. Diese Aussage ist inzwischen deutlichst veraltet, vo einigen Jahren hätte ich sie noch gelten lassen, heutzutage ist die aber überholt. Die einzige sinnvolle Formatierung für Einrückungen sind Tabulatoren.

Zur Begründung *g*:

Inzwischen ist jeder gängige Editor (SynEdit, UltraEdit, emacs, sogar vim, natürlich die Delphi-IDE und viele viele andere (Notepad sei hier mal ausgeschlossen)) bei der Darstellung der Tabs anpassbar.

Will heissen: Jeder Entwickler definiert für sich und für seinen Editor seine persönliche Einrückungstiefe, mit der Tabs dargestellt werden.

Wird nun für jede Einrückungsebene genau ein Tab verwendet, wird dies in jedem gängigen Editor korrekt und gleichmässig eingerückt angezeigt. Von Zerstörung der Formatierung kann hier gar keine Rede sein.

In dem Fall kannst Du also hergehen und Deine Einrückungsebene auf 2 Zeichen stellen, ich stelle meine auf 3 Zeichen, jeder hat seinen Code für ihn übersichtlich eingerückt und ich brauch mich nicht aufregen wenn ich von Dir nen Code bekomme, bei dem die Blöcke so eng aufeinandersitzen das man sie kaum unterscheiden kann bei nur 2 Zeichen
Sebastian Gingter
Phoenix - 不死鳥, Microsoft MVP, Rettungshundeführer
Über mich: Sebastian Gingter @ Thinktecture Mein Blog: https://gingter.org
  Mit Zitat antworten Zitat
Benutzerbild von Phoenix
Phoenix
(Moderator)

Registriert seit: 25. Jun 2002
Ort: Hausach
7.640 Beiträge
 
#53

Re: Codedesign

  Alt 14. Nov 2003, 08:29
Zitat von neolithos:
Records das "r"
Pointer ein "p" + typen-präfix
z.B. Pointer auf einen Integer "pi"
Constanten "c" + typen-präfix
Übertragungsparameter "a" + typen-präfix

Das ist aber wahrscheinlich Ansichtsache.
Japp.

Ich selber beschreibe nicht explizit, was das für ein Typ ist, sondern nur welchen Gültigkeitsbereich die Variable hat.
Code:
g_   global variables
a_   arguments   
l_   local variables
m_   member variables
i_   inline implementations
Inlines sollte man imho vermeiden, aber ab und kann man sie doch ganz gut gebrauchen.

Diese Notation hat den Vorteil, daß ich jederzeit im Code genau erkennen kann, woher eine Variable kommt. Wenn ich in einem Codestück ein a_FileName sehe, dann weiss ich, daß ich in der Argumentliste im Methodenkopf nachgucken wenn ich mich wundere warum da kein String drin ist. Wenn ich über ein g_forCounter stolpere weiss ich auch, daß sich der Entwickler keine Gedanken um sein Codedesign gemacht hat

Ausnahme von der Regel: i,j,s,t (die typischen lokalen Counter- und Stringvariablen halt) werden nicht mit l_ eingeleitet: l_i sieht bescheuert aus, und bei i weiss sowieso jeder das das ein Integer ist und wahrscheinlich als Schleifencounter verwendet wird.
Sebastian Gingter
Phoenix - 不死鳥, Microsoft MVP, Rettungshundeführer
Über mich: Sebastian Gingter @ Thinktecture Mein Blog: https://gingter.org
  Mit Zitat antworten Zitat
Chewie

Registriert seit: 10. Jun 2002
Ort: Deidesheim
2.886 Beiträge
 
Turbo Delphi für Win32
 
#54

Re: Codedesign

  Alt 14. Nov 2003, 15:27
Zitat von Luckie:
Speziell an Hagen noch mal:

Du hast auf Seite 1 oder 2 folgende Aussagen gemacht:

in den Thread hats du folgende Aussagen getroffen:
  • 3 ordinale Paramter maximal für Proceduren
  • 2 ordinale Paramter maximal für Methoden (Self ist der 3. unsichtbare Parameter)
  • register Aufrufkonvention wenn möglich
  • Result immer nur am Ende der Funktion belegen, oder vor einem Exit;
  • möglichst wenige lokale unkomplizierte Variablen
  • das Aufsplitten komplexer Funktionen auf mehrere weniger komplexe Funktion macht den Code meistens schneller, da der Optimierer besser arbeiten kann (gilt auch für nested Proceduren)
Könntest du die mir bitte noch mal erleätern / begründen? Die Hintergründe hierzu wären nicht schlecht zu erfahren. Danke.

*handheb* Wenn ich auch versuchen darf:
Zitat:
3 ordinale Paramter maximal für Proceduren
Es gibt 4 allgemeine CPU-Register: EAX, EBX, ECX und EDX. Eines davon, ich glaub EBX (oder ECX) wird vom Betriebssystem ständig verwendet, die anderen stehen dem Benutzer zur Verfügung. Wenn man nun die richtige Aufrufkonvention verwendet, nämlich register, werden so viele Parameter wie möglich in die Register geschrieben und nicht in den RAM (Stack). Bei max. 3 Parametern ist also alles im Register. Dazu ist noch zu sagen, dass es Ordinal-Typen sein sollen, oder, komplexen Dateitypen, Zeiger auf diese (deswegen auch const bzw. var). Denn in ein Register passen 4 Byte, aber kein 32-Byte-Record.
Registeraufrufe sind schneller, da Daten sowieso erst in Registern verarbeitet werden. Sind sie im Speicher, müssen sie erst in ein Register kopiert werden.

Beispiel:
(a sei Variable, also Speicheradresse)
Code:
ADD a, 10
ist eigentlich:
Code:
MOV EAX,a
ADD EAX,10
MOV a, EAX
Zitat:
2 ordinale Paramter maximal für Methoden (Self ist der 3. unsichtbare Parameter)
ergibt sich aus dem ersten, bei einer Methode wird immer ein dritter Parameter Self übergeben

Zitat:
Result immer nur am Ende der Funktion belegen, oder vor einem Exit;
Der Rückgabewert einer Funktion stehz am Ende in EAX. Wenn also nach dem Belegen des Rückgabewerts noch Aktionen ausgeführt werden, die das Regsiter EAX beanspruchen, wird das Result im Speicher abgelegt und muss am Ende in EAX kopiert werden.
Wird danach nix mehr gemacht, wird das Result sofort in EAX geschrieben und es muss nix mehr kopiert werden.

So, ich hoffe, das war soweit korrekt, aber den Rest sollte wirklich Hagen erklären
Martin Leim
Egal wie dumm man selbst ist, es gibt immer andere, die noch dümmer sind
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#55

Re: Codedesign

  Alt 14. Nov 2003, 16:27
Danköööö.
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#56

Re: Codedesign

  Alt 6. Jan 2004, 01:51
So, habe mal etwas dran gearbeitet. Das letzte Kapitel "4. Auch die Werkzeuge muss man kennen" macht mir noch etwas Kummern. Es ist noch etwas mager. Wenn da noch jemand eine Idee hat, wie man das ergänzen und damit das ganze abrunden könnte, nur her damit. Sollten es größere Beiträge werden, ist natürlich auch eine Nennung als Co-Autor drin. Logisch.

Ich Depp, ich wollte es ja anhängen.
Angehängte Dateien
Dateityp: pdf codedesign_474.pdf (172,4 KB, 33x aufgerufen)
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#57

Re: Codedesign

  Alt 6. Jan 2004, 02:29
Zitat:
3 ordinale Paramter maximal für Proceduren
2 ordinale Paramter maximal für Methoden (Self ist der 3. unsichtbare Parameter)
register Aufrufkonvention wenn möglich
Bei der Aufrufkonvention "register" gelten folgende Regeln
1.) register ist die Standardaufrufkonvetion, wenn nicht explizit anderes deklariert wurde
2.) register über gibt die ersten 3 Parameter immer in den Registern EAX,EDX,ECX wenn der Parametertyp ordinal oder per Referenz auf einen Ordinalen Typ ist
3.) Methoden sind standardmäßig register deklariert
4.) Methoden nutzen als ersten odinalen Parameter den versteckten Parameter Self, somit haben wir nur noch die zwei Register EDX,ECX zur Verfügung
5.) bei Proceduren mit mehr als 3 oder aber Methoden mit mehr als 2 Parametern werden die restlichen Parameter auf dem Stack übergeben
6.) Fließkomma Paramater sind IMMER eine Ausnahme, sie werden nie in direkt in Registern übergeben, sondern immer by Reference
7.) Komplexe Rückgabe Paramater bei Funktionen werden ebenfalls als Referenz in den Stack Speicher als letzter Paramater übergeben. Darunter fallen zB. Records oder Interfaces oder ShortStrings, aber nicht LongStrings


Zitat:
Result immer nur am Ende der Funktion belegen, oder vor einem Exit;
Der Optimierer versucht als erste wichtige Maßnahme die häufigst benutzten lokalen ordinalen Variablen in Register zu optimieren. Sollten nicht genügend Register vorhanden sein um alle Lokale Variablen plus der ordinalen Resultat Variablen in Registern zu speichern, so gerät der Optimierer und Druck, eg. Zugzwang. Als erstes wird er das Resultat als temporäre lokale Variable anlegen. Beim Exit aus der Funktion wird dann dieser Inhalt in Register EAX kopiert. Ausnahme sind Fließkomma oder komplexe Datentypen.
Angenommen die Funktion nutzt nur sehr wenige lokale Variablen, es stehen also genügend freie Register zur Verfügung. Wird nun denoch Result sofort in der Funktion benutzt, statt eben erst ganz ganz zum Schluß so wird der Optimier ein Register benutzt das NICHT EAX ist. Erst am Schluß wird er das benutzte Register, meistens ESI,EDI,EBX in das EAX Register kopieren. Dies bedeutet das wenn man das Resultat in eine selbstdefinierte lokale Variable berechnet und erst ganz zum Schluß Result := LokaleVariable setzt der Optimier nun Freiheiten gewinnt. Er kann also selbständig entscheiden wie und wo er diese Lokale Vaiable in welches Register optimiert. So oder so wird er am Exit der Funktion ein MOV EAX,reg durchführen.
Hintergund bei dieser Logik ist der Fakt das nachdem Resultat am Anfeng gesetzt wurde nun Aufrufe zu Unterproceduren erfolgen können. Er darf also NICHT EAX sofort als Resultat Register bentzen, da ja durch den Unteraufruf EAX,EDX,ECX jederzeit zerstört werden können. Desweiteren ist die Standardaufrufkonvention ja register, also EAX,EDX,ECX könnten bei Unterfunktionen als Paramater dienen. Nun, statt wie in C/C++ aufwendige Analysen durchzuführen haben die Borlandianer anders gedacht. Sie benutzen die Regel das EAX,EDX,ECX jederzeit zerstörbar sind und ESi,EDI,EBX immer innerhalb von Unterfunktionen durch diese gesichert werden müssen. Somit können die Register ESI,EDI,EBX ohne weitere Source-Analyse als Register-Lokale-Varibalen benutzt werden. Statt also wie in C/C++ auf alle Eventualitäten durch komplette Live-Analyse des gesammten Source zu optimieren, wie beim Borland Compiler von vornherein mit einem Regelwerk gearbeitet. Der Optimierer optimiert so als wäre es im Scheiß egal welche Unterfunktionen noch im Source stehen.
Nun, wird Result schon am Anfang der Procedure gesetzt so MUSS der Optimierer diesen Wert als unsichtbare temporäre lokale Variable auf dem Stack verwalten.

Zitat:
möglichst wenige lokale unkomplizierte Variablen
das Aufsplitten komplexer Funktionen auf mehrere weniger komplexe Funktion macht den Code meistens schneller, da der Optimierer besser arbeiten kann (gilt auch für nested Proceduren)
Auch bei diesen Tipps geht es darum dem Optimierer den Registerdruck zu nehmen, bzw. eben die Entscheidungs/Optimierungsfreiheiten zu erhöhen. Der Delphi Optimierer sieht das Innere einer Funktion als eigenständige und kleinste Optimierungseinheit an, bzw. BlackBox. Er weiß das EAX,EDX,ECX frei benutzt werden dürfen, das EDI,ESI nach deren Sicherung auf dem Stack frei benutzt werden können, und das EBX abhänig ob man Kylix Code erzeugt oder nicht ebenfalls nach der Sicherung auf dem Stack benutzt werden kann. Außnahme bei EBX sind nested Funktions. Bei solchen Funktionen wird der Compiler EBX als indirekten Stack-Pointer-Index benutzen um auf den übergeordneten Stack zuzugreifen. Allerdings NUR wenn in der nested Funktion auch wirklich Code steht der auf übergeordnete Variablen zugreift.

Nun, als erstes wird der Optimierer abhänig von der Komplexität entscheiden ob er die Übergabeparameter der Funktion zwischenspeichern muß. Wenn NICHT das entsteht die optimialste Form einer Funktion. Input über EAX,EDX,ECX, Berechnung nur mit EAX,EDX,ECX und Rückgabe über EAX. Falls aber Lokale Variablen existieren und Registerdruck ermittelt wird wird der Optimierer an´fangen ESI,EDI und eventuell EBX auf den Stack zu sichern. Danach werden die Paramater in EAX,EDX,ECX ind ESI,EDI kopiert. Dies trifft zB. fast immer bei Methoden zu, d.h. Self in EAX landet am Anfang der Methode in ESI. Das wird gemacht damit eventuelle Unterproceduren und methoden die wiederum Self benötigen OHNE Stackzugriffe über ESI Self zur Verfügung haben. Vor dem Aufruf einer solchen Unter-Methode wird der Compiler also ESI wieder nach EAX kopieren. Bei zB. 5 solcher Aufrufe würde er als 1. ESI pushen, 2. ESI=EAX setzen, 3. dann 5 mal EAX=ESI setzen und die Untermethoden aufrufen. Dies kommt mit 2 Stackzugriffen aus zum Pushen und Poppen von ESI. Würde man Self im Stack speichern so müsste der Compiler vor jedem Aufruf der 5 Untermethoden einen Stackzugriff durchführen um EAX korrekt zu laden.
Steigt die Komplexität der Funktion/Methode weiter an, so wird der Compiler die Taktik ändern. Er betrachten Schleifen als eigenständige Blacboxes und versucht nun inerhalb der Schleifen die Register gut zu nutzen. Z.b. preferiert er als Zählvaribale ein Register plus ein Register als Zeiger auf die Daten plus ein Register als Datenkontainer. Innerhalb der Schleife wird er nun per indirekter Addressierung mit Hilfe der Zählvaribalen im Register die daten in das Datenregister laden.


Gruß Hagen
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#58

Re: Codedesign

  Alt 6. Jan 2004, 02:39
Puh, ich erlaube mir das mal so zu übernehmen. Ich glaube, besser kann man es nicht erklären.
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#59

Re: Codedesign

  Alt 6. Jan 2004, 02:48
Naja, die Fehler in der Rechtschreibung sollten entfernt werden.

Ach wichtig ist auch noch folgende Information. Der Optimierer hat in keienr Delphi version einen Algortihmus zur Entfernung redundanter Register-Inhalte. Angenommen vor einem Unter-Methoden-Aufruf lädt der EAX aus ESI/EDI oder Stack. Danach ruft er die 1. Untermethode auf die NICHT EAX modifieziert. Nun beim nächsten Aufruf der 2. Untermethode wird er wiederum EAX aus ESI/EDI/Stack laden, obwohl EAX eigentlich schon Self enthält.

Dies ist absolut logisch das der Borland Compiler/Optimier NIEMALS Procedure/Funkction/Methoden übergreifen optimiert. Dies steht im Gegensatz zum C/C++ Compiler.

Wie immer gibt es sehr viele Ausnahmen, zB. eben die Fließkomma Berechnungen und deren Paramater. Das komplette Fließkommahandling des Optimierers muß vollständig losgelösst vom Rest des Optimierers betrachtet werden. In Punkto Fließkomma-Optimierung gilt nur eine einzigste Aussage über den Optimierer = er existiert NICHT, d.h. Fließkomma-Opertionen werden so gur wie überhaupt nicht optimiert !

Gruß Hagen
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#60

Re: Codedesign

  Alt 6. Jan 2004, 03:09
Zitat von negaH:
Naja, die Fehler in der Rechtschreibung sollten entfernt werden.
Schon geschehen.
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 6 von 6   « Erste     456   


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:52 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz