Lokale Variablen in Schleifen?



  • Einen wunderschönen guten Abend
    Ich frage mich gerade, ob es wohl einen Unterschied macht, ob ich:

    int a;
    
    for(int i=0;i<10000;++i){
     a = 0;
    
     for(int k=0;k<1000;++k) a += k;
    }
    

    und

    for(int i=0;i<10000;++i){
     int a = 0;
    
     for(int k=0;k<1000;++k) a += k;
    }
    

    Also konkret, ob es einen Performanzunterschied macht, ob ich so eine Variable innerhalb einer Schleife deklariere oder nicht. Ich könnte mir vorstellen, dass der Kompiler das dann doch ausserhalb der Schleife deklariert?

    Mfg Samuel



  • Ich würde sagen, dass der Compiler eh den gleichen Maschinencode generiert. Vielleicht interessiert dich ja wie der stack organisiert ist: http://www.cs.utk.edu/~plank/plank/classes/cs360/360/notes/Assembler1/lecture.html


  • Mod

    @jesus was black: Dein Link funktioniert nicht

    Und ja: Wenn überhaupt, dann ändert sich bloß die Position von a auf dem Stack. Bei der Definition von primitiven Typen wie int passiert ja nichts im Prozessor, das ist einfach nur eine Speicherzelle die benutzt wird. Bei Klassen mit komplexem Konstruktor/Destruktor sieht die Sache natürlich ganz anders aus, aber das sollte wohl klar sein.



  • Naja, ich frage mich, ob er den Stackzeiger erst dann anpasst, wenn ich die variable definiere => Also sub esp,0h04, oder ob er sämtliche lokalen Variable innerhalb einer Methode oder Funktion nimmt, deren Speicherbedarf zusammenzählt und schliesslich ein einziges mal ein sub macht?


  • Mod

    Oh, jetzt bin ich baff: g++ ohne alle Optimierungen erzeugt tatsächlich anderen Maschinencode. Der relevante Abschnitt:

    Variante 1:

    call	___main
    	movl	$0, -4(%ebp)
    	movl	$0, -8(%ebp)
    L2:
    	cmpl	$9999, -8(%ebp)
    	jg	L3
    	movl	$0, -12(%ebp)
    L5:
    	cmpl	$999, -12(%ebp)
    	jg	L4
    	movl	-12(%ebp), %eax
    	leal	-4(%ebp), %edx
    	addl	%eax, (%edx)
    	leal	-12(%ebp), %eax
    	incl	(%eax)
    	jmp	L5
    L4:
    	leal	-8(%ebp), %eax
    	incl	(%eax)
    	jmp	L2
    L3:
    	movl	$0, %eax
    	leave
    	ret
    

    Und Variante 2:

    call	___main
    	movl	$0, -4(%ebp)
    L2:
    	cmpl	$9999, -4(%ebp)
    	jg	L3
    	movl	$0, -8(%ebp)
    	movl	$0, -12(%ebp)
    L5:
    	cmpl	$999, -12(%ebp)
    	jg	L4
    	movl	-12(%ebp), %eax
    	leal	-8(%ebp), %edx
    	addl	%eax, (%edx)
    	leal	-12(%ebp), %eax
    	incl	(%eax)
    	jmp	L5
    L4:
    	leal	-4(%ebp), %eax
    	incl	(%eax)
    	jmp	L2
    L3:
    	movl	$0, %eax
    	leave
    	ret
    

    Der Unterschied ist, dass die movl Anweisung aus Zeile 3 der ersten Variante ein paar zeilen nach unten gerückt wird und somit innerhalb der Schleife liegt die sich von Label L2 bis L3 erstreckt. Das heißt, dass diese Anweisung tatsächlich 10.000 Mal ausgeführt wird anstatt 1x. Soviel also zu vorschnellen Verlautbarungen, dass es keinen Unterschied macht.



  • Ohne alle Optimierungen wundert mich garnicht dass anderer Code rauskommt.
    Ohne alle Optimierungen interessiert aber keinen. Also zumindest mich nicht.



  • hustbaer schrieb:

    Ohne alle Optimierungen interessiert aber keinen. Also zumindest mich nicht.

    Mich auch nicht.


Anmelden zum Antworten