Compiler-Optimierungen ?
-
Hallo,
ich programmiere derzeit auf Graphen und heute sind folgende Fragen bei mir aufgekommen:
1.) Angenommen, ich habe eine Funktion, in der folgende Situation vorkommt:
Ich arbeite auf structures, die untereinander irgendwie verknüpft sind. In der Funktion arbeite ich auf einer structure, die durch längere Pointer-Ketten aus den Aufrufparametern gegeben ist (z.B. graph->knoten->kante->endknoten->...->ziel). Nun benutze ich zur Übersichtlichkeit des Codes die Vereinfachung, dass ich am Anfang der Funktion folgende Variable definiere:help= graph->...;
Danach arbeite ich mit "help" weiter und der Code sieht einfacher aus.
Frage: Erkennt der Compiler, wenn er nachher den Code kompiliert, dass diese Variable "help" eigentlich überflüssig ist und optimiert sie raus oder kostet mich die Übersichtlichkeit des Codes hier (ein wenig) Speicherplatz? Wie sieht es laufzeitmäßig mit ewig langen Pointer-Ketten (wie oben) aus? Da muss sich ja auch erstmal durchgehangelt werden oder braucht man sich auch da keine Gedanken, weil der Compiler es optimiert?
2.) Frage Nr.2 befasst sich mit dem geliebten i++ und ++i.
Vorweg: Mir ist der Unterschied bekannt. Nur denke ich mir, dass bei i++ i sozusagen zweimal gespeichert werden müsste, da man ja den alten Wert für die Expression und den neuen Wert für i nach der Erhöhung speichern muss, während das bei ++i nicht der Fall sein sollte (hier nur der neue Wert). Wäre es dann nicht schlauer, zB bei Schleifen stets ++i anstatt i++ zu benutzen oder nimmt sich das nichts?Mir geht es dabei gar nicht so sehr darum, ob jetzt der Speicherbedarf für die Hilfsvariable bzw. beim ++i/i++ oder der Laufzeitverlust beim Pointer-Durchhangeln minimal ist oder nicht - ich möchte erstmal einfach nur wissen, ob es ihn gibt. Ob er dann in einer Größenordnung liegt, wo man ihn völlig vernachlässigen kann oder ob man auf sowas achten sollte, wäre dann die zweite Frage.
-
Generiere dir selbst den Assemblercode und schaue nach.
-
plizzz schrieb:
Nun benutze ich zur Übersichtlichkeit des Codes die Vereinfachung, dass ich am Anfang der Funktion folgende Variable definiere:
help= graph->...;
Danach arbeite ich mit "help" weiter und der Code sieht einfacher aus.
Frage: Erkennt der Compiler, wenn er nachher den Code kompiliert, dass diese Variable "help" eigentlich überflüssig ist und optimiert sie raus oder kostet mich die Übersichtlichkeit des Codes hier (ein wenig) Speicherplatz?
Wird wegoptimiert.
plizzz schrieb:
Wie sieht es laufzeitmäßig mit ewig langen Pointer-Ketten (wie oben) aus? Da muss sich ja auch erstmal durchgehangelt werden oder braucht man sich auch da keine Gedanken, weil der Compiler es optimiert?
Da kann der Compiler nicht optimieren, schließlich muss er immer durchhangeln. Sonst kann er ja nicht wissen, wo die nächsten Elemente liegen (werden ja zur Laufzeit allokiert).
plizzz schrieb:
2.) Frage Nr.2 befasst sich mit dem geliebten i++ und ++i.
Vorweg: Mir ist der Unterschied bekannt. Nur denke ich mir, dass bei i++ i sozusagen zweimal gespeichert werden müsste, da man ja den alten Wert für die Expression und den neuen Wert für i nach der Erhöhung speichern muss, während das bei ++i nicht der Fall sein sollte (hier nur der neue Wert). Wäre es dann nicht schlauer, zB bei Schleifen stets ++i anstatt i++ zu benutzen oder nimmt sich das nichts?Wird optimiert.
-
plizzz schrieb:
Wie sieht es laufzeitmäßig mit ewig langen Pointer-Ketten (wie oben) aus? Da muss sich ja auch erstmal durchgehangelt werden oder braucht man sich auch da keine Gedanken, weil der Compiler es optimiert?
Das hängt vom konkreten Fall ab. Der Compiler wird schon versuchen, das Ergebnis des "Durchhangelns" zwischenzuspeichern, um es nicht in einer Schleife immer wieder machen zu müssen. Aber manchmal geht das nicht, da der Compiler nicht ausschließen kann, dass in einer zwischendurch aufgerufenen Funktion etwas in der Kette verändert wird. Daher kann so eine "help"-Variable sinnvoll sein. Aber man sollte solche Handoptimierungen nicht übertreiben, weil man dadurch leicht den Code unleserlich machen kann.
In bestimmten Fällen kann man dem Compiler auch mit dem in C99 hinzugekommenen restrict-Schlüsselwort bei solchen Optimierungen helfen.
-
plizzz schrieb:
2.) Frage Nr.2 befasst sich mit dem geliebten i++ und ++i.
Vorweg: Mir ist der Unterschied bekannt. Nur denke ich mir, dass bei i++ i sozusagen zweimal gespeichert werden müsste, da man ja den alten Wert für die Expression und den neuen Wert für i nach der Erhöhung speichern muss, während das bei ++i nicht der Fall sein sollte (hier nur der neue Wert). Wäre es dann nicht schlauer, zB bei Schleifen stets ++i anstatt i++ zu benutzen oder nimmt sich das nichts?Prinzipiell kann der Compiler das so machen:
b = ++a; // daraus kann er machen: a += 1; b = a; b = a++; // daraus kann er machen: b = a a += 1;
Kein Unterschied aus der Sicht von C. Ob eines davon auf einer bestimmten Architektur leichter zu forumulieren ist, ist schwer zu sagen.
-
Ok, dann werde ich weiterhin meine help-Variablen verwenden und die for-Schleifen mit i++ durchgehen.
MfG plizzz
-
In C macht in den for-Schleifen ++i und i++ kein Unterschied. Ich habe mir aber ++i deshalb angewöhnt, weil in C++ schon ein Unterschied geben kann, wenn i kein Integer ist und ++i schneller ist.
-
supertux schrieb:
weil in C++ schon ein Unterschied geben kann, wenn i kein Integer ist und ++i schneller ist.
Das wird auch in C++ wegoptimiert.
-
Janjan schrieb:
supertux schrieb:
weil in C++ schon ein Unterschied geben kann, wenn i kein Integer ist und ++i schneller ist.
Das wird auch in C++ wegoptimiert.
Aber nur bei nicht überladenen Operatoren, bei Iteratoren z.B. kann der Compiler das nicht wegoptimieren (sonst müsste er ja wissen, was in der Funktion vor sich geht).
-
DerKuchen schrieb:
Aber nur bei nicht überladenen Operatoren, bei Iteratoren z.B. kann der Compiler das nicht wegoptimieren (sonst müsste er ja wissen, was in der Funktion vor sich geht).
Eigentlich schon, weil die inline sind.
-
volkard schrieb:
DerKuchen schrieb:
Aber nur bei nicht überladenen Operatoren, bei Iteratoren z.B. kann der Compiler das nicht wegoptimieren (sonst müsste er ja wissen, was in der Funktion vor sich geht).
Eigentlich schon, weil die inline sind.
Stimmt, so weit hab ich gar nicht gedacht...