Programmier-"Niveau"



  • Och ja, ich hab ja am Anfang ein paar brauchbare Antworten bekommen, streitet euch mal ruhig über den Quatsch, ist doch lustig. Aber könnte mich eben jemand auf den neuesten Stand bringen, ich habe irgendwie den Faden verloren. Irgendwas mit Stack gehört zu RAII oder nicht oder so. 😃



  • Xin schrieb:

    hustbaer schrieb:

    Und nochwas: du redest hier (wenn du mit mir redest) nicht mit einem Vollidioten. Ich habe eine sehr genaue Vorstellung davon was Compiler so machen, wie der übersetzte Code so aussieht etc. Und auch eine halbwegs gut davon was verschiedene Compiler so für Optimierungen durchführen können. Das "aus 3 mach 2" Beispiel ist z.B. keineswegs erfunden.

    Die Variable wird nie im Registerlanden, sondern das Objekt, dass die Variable identifiziert.
    Nehmen wir "i". Behaupten wir, dass "i" auf dem Stack bei -4 liegt. Das Objekt, dass mit "i" identifiziert werden soll, hat also das Offset -4 zum Stack und heißt im Quelltext eben "i". Das ist Deine Variable.
    Die Optimierung greift. Sie lädt das Objekt, welches sich 4 Bytes vor dem Stackpointer befindet als 32 Bit Datenwert in das Register und iteriert über das Register.

    Nur dass i überhaupt nirgends mehr existiert. Es existiert dann lediglich der Wert des Ausrducks &p[i] in einem Register (das ist die neue Variable p2 in meinem Beispiel). Es gibt im optimierten Programm *nichts* mehr das i entspricht, keine einzige Speicherstelle/Register/... wo also z.B. 23 drinstehen würde wenn die Schleife sich im Durchlauf i == 23 befindet.

    Dafür gibt es ein neues "Ding" das im Source-Code keinen Namen hat: den Ausdruck &p[i] .

    Ich hab' dazu mal eine halbwegs high-level gehaltene Beschreibung des LLVM Optimizers/Code-Generators gelesen (hab leider keinen Link mehr dazu parat, falls jmd. die Beschreibung kennt... würde ich selber gerne nochmal lesen). Vorausgesetzt ich hab das richtig verstanden, dann macht der LLVM...

    a) Primär erstmal Register-Allocation mit virtuellen Registern, von denen es beliebig viele gibt. Aus diesen virtuellen Registern macht dann der Code-Generator Code der mit echten Registern und/oder Stack arbeitet - wie es halt gerade passt.

    b) Die Register-Allocation wird nicht nur für Variablen gemacht, sondern für sämtliche Zwischenergebnisse.
    Und dann wird weggeworfen was weggeworfen werden kann.
    Dadurch kann es leicht sein dass für ein Codestück weder die Variable "a" noch die Variable "b" übrigbleiben, der Ausdruck "a+b" überlebt aber.

    c) Wenn es eine Zuweisung im Code gibt, dann wird für den neuen Inhalt der Variable nach Programmstelle X eine neue Register-Allocation gemacht. D.h. selbst wenn die Variable "a" übrig bleibt kann es sein dass sie munter verschiedene Register durchwandert, vielleicht sogar zwischendurch mal auf dem Stack landet etc. Oft wird das keinen Sinn machen, und der generierte Code wird genau ein Register für eine Variable verwenden. Manchmal macht es aber Sinn, nämlich z.B. wenn der Code-Generator out-of-order Code generiert, und daher einen alten Wert einer Variable braucht nachdem diese bereits modifiziert wurde.

    Und sogesehen halte ich es für sehr irreführend zu sagen dass eine Variable einem Offset/einer Adresse/einem Register entspricht.
    Weil es eben nur bestimmte Spezialfälle sind wo man eine solche Zuordnung sinnvoll herstellen kann.

    Man kann von mir aus gerne sagen dass es "oft" so ist, z.B. wenn man einem Anfänger erklären will was da so ca. ungefähr passiert, aber als absolutes Statement ist es für mich halt einfach falsch.

    Xin schrieb:

    Die For-Schleife erlaubt nicht die Entfernung des Objektes, sie erlaubt aber, dass i nie auf dem Stack angelegt werden muss, in dem sofort das Register mit 0 initialisiert wird. Die Variable i muss kein Objekt auf dem Stack identifizieren und auch keine statische Adresse. Hier muss sie das Register addressieren, dass durch die Optimierung statt der stackrelativen Position ausgewählt wurde.
    Hier wird nichts rausoptimiert, hier wird nur in die CPU verlagert.

    Siehe oben.
    Wie kann die Variable i ein Register adressieren (oder eine wie auch immer geartete Sache wo man einen Wert abspeichern kann), wenn es *nichts* mehr im gesamten Computer gibt wo der Wert abgespeichert wäre der in i stehen würde/sollte/müsste?
    Gleichzeitig ist die Variable i auch nicht vollständig entfernt worden, denn sie kann nunmal einfach nicht vollständig entfernt werden. Dafür hat der Compiler das mit Hilfe der Variable i beschriebene verhalten anders umgesetzt: er hat die neuen "Variablen" (Ausdrücke, Register, ... wie auch immer man es nennen will) &p[i] und &p[len] eingeführt.

    Xin schrieb:

    Nach dem Compilervorgang ist die Variable komplett weg, das Objekt, das mit 'i' identifiziert wurde, existiert weiterhin im Register.

    Ich wiederhole mich jetzt, aber egal...
    Das mit i identifizierte Objekt ist vollkommen weg, übrig bleiben nur neue Dinge die das vom Programm beschriebene Verhalten umsetzen.
    Der Compiler verwendet hier das was unter C++lern gern als "as-if rule" bezeichnet wird: das beobachtbare Verhalten des Programms muss genau das selbe sein wie wenn ("as if") das originale Programm ausgeführt würde. Die Beibehaltung irgendwelcher nicht beobachtbaren Konstrukte wie z.B. die "direkte" Umsetzung lokaler Variablen ist nicht vorgeschrieben. Und daher erzeugen Compiler auch gerne mal Code wo es keine direkte Entsprechung zu lokalen Variablen mehr gibt.
    (Die "as-if" Regel findet man vermutlich auch in den meisten anderen Sprachen, ich beziehe mir hier nur auf C++ da ich sie von C++ her kenne und mich mit anderen Sprachen wesentlich weniger gut auskenne).

    Falls Du doch fachlich(!) mit mir diskutieren möchtest, dann gerne, aber nicht hier.

    Sondern lieber wo?
    Wir können das auch gerne per Email fortsetzen falls dir das lieber wäre. Oder einen neuen Thread aufmachen - nur dass dort dann sofort wieder 27 andere Leute mitposten würden, würde also vermutlich nix bringen.

    ps: natürlich *kann* ein Compiler so arbeiten dass es (abgesehen von Fällen wo etwas komplett wegoptimiert wird) immer eine 1:1 Zuordnung Variable <-> Adresse/Offset/Register gibt. Er *muss* aber nicht, und Compiler die richtig gut optimierten Code erzeugen können das mMn. auch nichtmal. Weil sich durch diese Einschränkung eben einfach zu viele Optimierungsmöglichkeiten verbieten würden.



  • hustbaer schrieb:

    Und sogesehen halte ich es für sehr irreführend zu sagen dass eine Variable einem Offset/einer Adresse/einem Register entspricht. ...

    Man kann von mir aus gerne sagen dass es "oft" so ist, z.B. wenn man einem Anfänger erklären will was da so ca. ungefähr passiert, aber als absolutes Statement ist es für mich halt einfach falsch.

    Ich kürze das mal ein wenig ab, um dieses Topic in diesem Thread mal zu einem Ende zu bewegen...

    Die Optimierung von Maschinencode ist ungefähr das letzte, was man einem Anfänger erklärt. Und man erklärt sie auch nicht, damit ich Shade begreiflich machen kann, dass ich RAII und die Programmierung allgemein aus einer ganz anderen Perspektive betrachte als ein Anwendungsentwickler.

    Mein Statement über Variablen gilt auch nicht für die Nachverarbeitung durch einen Maschinencode-Optimierer, sondern ganz allgemein. i ist auch eine Objekt und eine Variable(=Objektidentifizierer), wenn es nie benutzt wird.

    Was daraus wird, wenn der Maschinencode durch den Fleischwolf gedreht wird, das ist eine ganz andere Frage - hier findet quasi ein neuer Compiliervorgang statt, der nur noch mit Objekten abläuft und vollkommen ohne ein Dictionary, wie welches Objekt für den Anwendungsentwickler mal geheißen hat. Und das ist vor allem eine Frage, die überhaupt nichts mit dem ursprünglichen Topic zu tun hat. Wenn ich also hier keine vollständige Abhandlung in allein Einzelheiten schreibe, die die Registerverteilung bei der Maschinenspracheoptimierung beinhaltet, dann liegt das auch daran, dass das hier einfach nicht das Thema ist. Und ein Anfänger hat sich eventuell schon bei RAII verabschiedet, was auch nicht das Thema hier war. Da wurde genauso detailverliebt jedes Bit angesehen, weil ich RAII als Buzzword bezeichnet habe für Objekte, deren Speichermanagement durch den Stack gemanagt werden.
    Ich bin genauso detailverliebt, denn ich implementiere derartige Details und lasse mich dann leider auch zu gerne dazu hinreißen nach möglicherweise unverstanden oder schlecht verstandenen Details zu forschen. Aber das alles hat nichts in diesem Thread zu suchen oder wäre auch nur annähernd etwas, was jemand, der nicht wirklich scheiße tief in der Materie steckt noch interessiert.

    An dem Link wäre ich unabhängig von diesem Thread allerdings auch interessiert, falls Du ihn wiederfindest... ^^ (PN?)
    Das wäre nämlich genau meine Materie. ^^

    hustbaer schrieb:

    Wir können das auch gerne per Email fortsetzen falls dir das lieber wäre.

    Mail klingt gut.



  • Wenn ihr nicht bald aufhört, werde ich absofort dich, hustbaer, Keuchhusten oder Raucherhusten nennen und dich Xin, "nix" oder "niX" (deinen Namen von hinten nach vorne gelesen)! 😡



  • Steffo schrieb:

    Wenn ihr nicht bald aufhört, werde ich absofort dich, hustbaer, Keuchhusten oder Raucherhusten nennen und dich Xin, "nix" oder "niX" (deinen Namen von hinten nach vorne gelesen)! 😡

    Wieso sind doch lebendes Beispiel für das Programmierer-Niveau.



  • Zeus schrieb:

    Wieso sind doch lebendes Beispiel für das Programmierer-Niveau.

    Genau. Alleine die Tatsache, dass sie sich so lange über so einen Kleinkram unterhalten können, zeigt schon, dass beide ein hinreichendes Interesse an sauberen Definitionen und Code haben, und das qualifiziert beide zu zumindest potentiell guten Programmierern. 😉



  • cooky451 schrieb:

    Zeus schrieb:

    Wieso sind doch lebendes Beispiel für das Programmierer-Niveau.

    Genau. Alleine die Tatsache, dass sie sich so lange über so einen Kleinkram unterhalten können, zeigt schon, dass beide ein hinreichendes Interesse an sauberen Definitionen und Code haben, und das qualifiziert beide zu zumindest potentiell guten Programmierern. 😉

    Ich bin nicht sicher, ob das ein Kompliment ist, aber ich befürchte, Du hast unabhängig davon Recht. ;-D



  • Xin schrieb:

    Und man erklärt sie auch nicht, damit ich Shade begreiflich machen kann, dass ich RAII und die Programmierung allgemein aus einer ganz anderen Perspektive betrachte als ein Anwendungsentwickler.

    Ja, du hast eine sehr einzigartige Sicht auf alle Dinge.

    zB diese Diskussion - eine Variable als Highlevel Konzept lehnst du ab, als Lowlevel Konzept ebenfalls. Eine Variable ist ein Mischding das mal da ist und mal nicht, aber doch irgendwie immer ein Offset auch wenn es sie garnicht gibt.

    Ich wette es gibt keinen 2. Menschen auf der Erde der das gleich sieht.

    👍



  • Shade Of Mine schrieb:

    Ja, du hast eine sehr einzigartige Sicht auf alle Dinge.
    ...
    Ich wette es gibt keinen 2. Menschen auf der Erde der das gleich sieht.

    Die Wette würdest Du verlieren und deine Zusammenfassung, die ich eines Quote nicht wert ist, spricht für sich.



  • Offtopic: (Ah ne, das war ja quasi das eigentliche Thema.)
    In meiner heutigen Java Übungsaufgabe an der Uni habe ich eine Vorlage bekommen, in der sie den Kontostand von Personen als double modelliert haben. Sehr geil. 😃



  • cooky451 schrieb:

    Offtopic: (Ah ne, das war ja quasi das eigentliche Thema.)
    In meiner heutigen Java Übungsaufgabe an der Uni habe ich eine Vorlage bekommen, in der sie den Kontostand von Personen als double modelliert haben. Sehr geil. 😃

    Uns versuchte man damals im ersten Semester die Idee von Klassen beizubringen, in dem man uns erklärte, wie man reelle Zahlen abbilden könnte. Dafür wurden Vorschläge gesammelt: Zähler und Nenner und diverses andere. Der Prof entschied sich für die ungeschickteste Lösung, die er selbst vorgeschlagen hat: Nämlich mit zwei Integern, die den Bereich vor dem Komma und den Bereich nach dem Komma repräsentieren.

    ReelleZahl( int vorKomma, int nachKomma )
    

    Ich stellte dann die Frage, wie dann Zahlen wie 1,01 erzeugt werden und was passiert, wenn Zahlen wie 1,1 und 1,12 addiert werden. Im Verlauf der Vorlesung wurden die Sätze immer länger und verschachtelter: Unter der Bedingung, dass die es nicht zum Zahlen beide die gleiche Anzahl von Nachkommastellen haben, die auch konstruierbar sind, die auch keinen Überlauf erzeugen, wenn man sie addiert (1,5 + 1,5 ergibt ja bekanntlich 2,10), dann gilt.... (irgendwas triviales wie dass das Ergebnis stimmt). In solchen Sätzen ging dann die ganze Vorlesung weiter, bis man zu dem Schluss kam, dass man die heutige Vorlesung besser vergessen sollte. 😉



  • @Xin: Das ist ein gutes Beispiel für rationale Zahlen. Da kommt dann auch kein 1,00001 vor. Überlauf kann man teilweise verhindern, wenn man den größten gemeinsamen Teiler findet und wenn in deiner rationalen Klasse 1,5 + 1,5 = 2,1 rauskommt, dann hast du sie eben schlicht falsch implementiert...



  • Naja, theoretisch könnte man das dann ja verkaufen als Lektion warum es wichtig ist die Daten richtig zu modellieren.

    Denn oft kann Code enorm viel besser werden, indem die Datenstruktur besser gewählt werden... Aber das hat der Prof da dann wohl auch nicht verstanden gehabt :p



  • Steffo:
    Ich versteh kein Wort. 1. hat Xin von reellen Zahlen gesprochen und 2. ist z.B. 1,00001 sehr wohl eine rationale Zahl, also was willst Du jetzt sagen?



  • Eisflamme schrieb:

    Steffo:
    Ich versteh kein Wort.

    Weil du mich nicht verstehen willst. 😛



  • Wenn Du damit meinst, dass hinter Deinen Worten meist nicht viel steckt, richtig. Darüber hinaus erscheinen mir die Aussagen aber auch falsch. Und ob falsch oder nicht, ich finde es dann auch noch unverständlich formuliert.

    Edit: Das war etwas hart ausgedrückt. Lass es mich einfach korrigieren: Ja.



  • Was ich damit sagen wollte: Man kann tatsächlich ein gutes OO-Beispiel für Zähler/Nenner konstruieren. Bei den reellen Zahlen mag das fehl am Platze sein, bei den rationalen aber nicht.



  • Ich glaube Steffo kann ein Nenner/Zähler Paar nicht von einem vorm Komma / nachm Komma Paar unterscheiden.



  • cooky451 schrieb:

    Ich glaube Steffo kann ein Nenner/Zähler Paar nicht von einem vorm Komma / nachm Komma Paar unterscheiden.

    Was ist denn ein / anderes als ein grosses , ?



  • cooky451 schrieb:

    Hi,

    mir fällt immer mehr auf, dass meine Vorstellung von "programmieren können" und die von den meisten anderen ziemlich weit auseinander geht.

    Als DAU, der tagtäglich die Qualitätsarbeit, die Programmierer bzw. Softwareentwickler so produzieren, bewundern darf, wundert mich das nicht.

    Z.B. bei einer namhaften Softwareschmiede für Datenbanken, deren Programm irgendwann in den 80er Jahren entwickelt wurde, als es noch 14/15-Zoll-Monitore gab.

    Mit heutigen 17 bzw. 19 Zöllern besteht die Darstellung auf dem Bildschirm dann zu einem Drittel oder so aus weißer Fläche, sprich die Leutz haben es in 20 Jahren nicht geschafft, ihre Software auf neue Monitore auszurichten.


Anmelden zum Antworten