Minimalbeispiel zur Darstellung effizienter Schleifen

Gast #1529195
Nabend,

ich versuche mich gerade an einem Minimalbeispiel:
1
#include <avr/io.h>
2
int main(void) {
3
  uint8_t i, n;
4
  for (i=0; i<17; i++) {
5
    n++;
6
  }
7
}

Daraus wird allerdings im .lss:
1
int main(void)
2
{
3
  b4:  80 e0         ldi  r24, 0x00  ; 0
4
  b6:  90 e0         ldi  r25, 0x00  ; 0
5
  b8:  08 95         ret
6

7
000000ba <_exit>:
8
  ba:  f8 94         cli
9

10
000000bc <__stop_program>:
11
  bc:  ff cf         rjmp  .-2        ; 0xbc <__stop_program>

Ich nehme an, dass durch das Makefile irgendwelche Optionen aktiviert 
werden, die die Schleife eliminieren.
Könnte das jemand bei sich testen oder mir ein Makefile mit 
funktionierenden Optionen zukommen lassen?
Gast #1529211
Es scheint mir aber irgendwie sinnfrei zu sein, zu untersuchen, wie eine 
effiziente Umsetzung einer Schleife durch den Compiler aussieht, wenn 
man dabei Optimierungen ausschaltet.
Der Beispielcode ist natürlich ähnlich sinnfrei, da einerseits n einen 
undefinierten Wert hat, andererseits ein 17maliges Inkrementieren von n 
das gleiche ist wie n += 17. Dazu kommt dann noch, daß weder i noch n 
für irgendwas verwendet werden, also optimiert der Compiler kurzerhand 
einfach alles komplett weg. So gesehen gäbe es keine Möglichkeit, die 
Schleife noch effizienter umzusetzen, als es der Compiler getan hat. ;-)
#1529228
Noch effizienter (allerdings nicht mehr standardkonform, GCC macht es 
aber trotzdem) wird es, wenn du den Rückgabetyp von main() auf void 
änderst. Dann hast du eine Funktion, die nichts macht, was irgendwas 
außerhalb von ihr bewirkt, und die nichts zurückgibt. Ergebnis der 
Optimierung:
ret
Effizienter geht es kaum noch, man könnte nur noch inlinen und sämtliche 
Aufrufe von main() rauschmeißen [was aber wohl kein Compiler machen 
würde, weil ne leere Main ja nicht gerade üblich ist]... Und wenn main() 
dann also nie aufgerufen wird, dann könnte man auch den Startup-Code 
weglassen... somit bleibt nicht übrig...
Gast #1529443
> 2.) Bei z.B. einem return n; dürfte der Compiler die Variable nicht so
> einfach wegoptimieren? Sonst zieht er sich ja den Rückgabewert unter den
> Füßen weg ;o)

Er muß in diesen Zeilen
1
 b4:  80 e0         ldi  r24, 0x00  ; 0
2
  b6:  90 e0         ldi  r25, 0x00  ; 0

einfach die 0 durch den Wert, den n nach der Schleife hätte, ersetzen.
Gast #1529466
>> Er muß in diesen Zeilen einfach die 0 durch den Wert, den n nach der
>> Schleife hätte, ersetzen.
>
> Da n einen undefinierten Anfangswert hat, ist 0 ein absolut korrekter
> return-Wert. ;-)

Allerdings. Das wollte ich eigentlich nicht weiter ausführen. Rein aus 
Interesse habe ich aber mal geschaut, was der Compiler denn tatsächlich 
daraus macht, und er entscheidet sich dafür, n wie mit 0 initialisiert 
zu behandeln, schreibt also einen Rückgabewert von 17 in die Register.

@jozi59:

> Zumal n auch überhaupt nicht als return value verwendet wird.

Vielleicht liest du besser nochmal nach, worauf ich geantwortet hatte.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 16 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.