Nieuws:

Welkom, Gast. Alsjeblieft inloggen of registreren.
Heb je de activerings-mail niet ontvangen?

Auteur Topic: [C++] Welke vorm van lussen is efficiënter?  (gelezen 1625 keer)

Offline Joshua822

  • Lid
[C++] Welke vorm van lussen is efficiënter?
« Gepost op: 2009/09/20, 01:22:21 »
Hallo.

Ik stuitte net erop dat je in C++ ook naar een bepaalde sectie code kan springen. Nu vroeg ik mij af, is dit zo bijvoorbeeld sneller dan met een do while lus bijvoorbeeld?:
Met goto statement:
#include <iostream>

using namespace std;

int main()
{
   unsigned int waarde (10);
   lus:
     cout << waarde << "\n";
     waarde--;
   if ( waarde > 0 ) goto lus;
   return 0;
}
Met een do while lus:
#include <iostream>

using namespace std;

int main()
{
   unsigned int waarde (10);
   do
   {
      cout << waarde << "\n";
      waarde--;
   } while ( waarde > 0 );
   return 0;
}

P.S: Ja, ik weet dat je een goto statement alleen in low level programmeren kunt toepassen.
Alvast bedankt.

Offline profoX

  • Lid
    • wesley
    • Lionslink
Re: [C++] Welke vorm van lussen is efficiënter?
« Reactie #1 Gepost op: 2009/09/20, 02:48:37 »
Goto is niet noodzakelijk sneller (compilers zijn goed in automatisch optimaliseren) maar wel sowieso minder duidelijk/overzichtelijk, minder flexibel... het gebruik van goto wordt afgeraden, tenzij je niet anders kan (zoals low-level assembler).

PS: de indentatie in je voorbeeldje zou je misschien doen vermoeden dat het even makkelijk te gebruiken is (in simpele omstandigheden) dan met bv. een while-lus, maar 1) als een while-lus toch even makkelijk is, waarom dan geen while-lus gebruiken en 2) bij een while-lus werk je in een afgesloten blok, maar bij een goto-statement kan je naar eender welk stuk code springen. Ook zal je telkens verschillende identifiers nodig hebben waardoor het helemaal niet flexibel is.
Human Knowledge Belongs To The World -- Antitrust (2001)
Nederlandstalige Ubuntu documentatie van Ubuntu-NL (wiki)

Offline profoX

  • Lid
    • wesley
    • Lionslink
Re: [C++] Welke vorm van lussen is efficiënter?
« Reactie #2 Gepost op: 2009/09/20, 03:02:07 »
Even een voorbeeldje:

int main() {
    int a = 10;
    do {
        --a;
    } while (a > 0);
    return 0;
}

genereert deze assembler-code:
.file "test.c"
.text
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $16, %esp
movl $10, -8(%ebp)
.L2:
subl $1, -8(%ebp)
cmpl $0, -8(%ebp)
jg .L2
movl $0, %eax
addl $16, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
.ident "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
.section .note.GNU-stack,"",@progbits

int main() {
    int a = 10;
    lus:
        --a;
    if (a > 0) goto lus;
    return 0;
}

genereert deze assembler-code:
.file "test.c"
.text
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $16, %esp
movl $10, -8(%ebp)
.L2:
subl $1, -8(%ebp)
cmpl $0, -8(%ebp)
jg .L2
movl $0, %eax
addl $16, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
.ident "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
.section .note.GNU-stack,"",@progbits

Zoals je kan zien (diff zal het je ook weten te vertellen) is de gegenereerde assembler-code exact hetzelfde. Dus goto geeft je in 99% van de gevallen geen enkel voordeel. Ook als je de binaries vergelijkt met diff zal je zien dat ze hetzelfde zijn.
Human Knowledge Belongs To The World -- Antitrust (2001)
Nederlandstalige Ubuntu documentatie van Ubuntu-NL (wiki)

Offline Double12

  • Lid
Re: [C++] Welke vorm van lussen is efficiënter?
« Reactie #3 Gepost op: 2009/09/20, 15:32:04 »
C++-code wordt toch door de compiler omgezet naar binaire code en niet naar assembler? Of bedoel je dit als theoretisch geval, als dat wel zou gebeuren?

En hoe kan een compiler zo gemaakt zijn dat twee dingen die heel verschillend geschreven maar toch als hetzelfde bedoeld zijn, dezelfde binaire code opleveren?

Offline track

  • Lid
Re: [C++] Welke vorm van lussen is efficiënter?
« Reactie #4 Gepost op: 2009/09/20, 20:08:36 »
Profox:  +1 !
Ik had het niet beter kunnen uitleggen.  En de "goto" is ook volgens mij
een "no-go"...   (tenzij je bent er op gewezen dit voor een trucje in te zetten)

Double12:
De assembler is maar de leesbare representatie van de machinecodes.
Je kunt het rechtstreeks omzetten (heen en weer).

track

Offline profoX

  • Lid
    • wesley
    • Lionslink
Re: [C++] Welke vorm van lussen is efficiënter?
« Reactie #5 Gepost op: 2009/09/20, 20:43:50 »
C++-code wordt toch door de compiler omgezet naar binaire code en niet naar assembler? Of bedoel je dit als theoretisch geval, als dat wel zou gebeuren?
Geen theoretisch geval. Onrechtstreeks genereert een compiler vaak code naar een intermediaire assembler-taal zodat de compiler gemakkelijker kan geporteerd worden naar verschillende platformen. In dit specifieke geval heb ik gcc gevraagd om slechts assemblercode te genereren zonder deze uiteindelijk te assembleren in een binair bestand. Dit is de manier waarop de meeste compilers werken. Met de -S switch van gcc kan je vragen om enkel assembler-code te genereren.

Simpel gezegd: De uiteindelijke machinecode is eigenlijk slechts een binaire representatie van het assemblerprogramma waarbij o.a. labels zijn omgezet naar relatieve of absolute geheugenadressen. Deze machinecode wordt dan verwerkt door een microprogramma dat in de processor zelf aanwezig is om de nodige signalen te sturen naar alle nodige bussen.

En hoe kan een compiler zo gemaakt zijn dat twee dingen die heel verschillend geschreven maar toch als hetzelfde bedoeld zijn, dezelfde binaire code opleveren?
Er bestaan geen lussen in de meeste low-level assemblertalen (MASM heeft ze bijvoorbeeld wel maar dat durf ik eigenlijk ook geen échte assemblertaal te noemen) dus onrechtstreeks worden lussen vaak wel omgezet naar jump statements (in mijn voorbeeld is dit de jg .L2 instructie, oftwel spring naar L2 als a > 0) Met een goto statement zou je dit dus meer direct kunnen sturen, maar zonder enig voordeel.

edit: ook dankzij optimalisatie die door de compiler wordt uitgevoerd kan dit gebeuren trouwens (met de -O# switches van gcc kan je dit aangeven)
« Laatst bewerkt op: 2009/09/20, 20:46:22 door profoX »
Human Knowledge Belongs To The World -- Antitrust (2001)
Nederlandstalige Ubuntu documentatie van Ubuntu-NL (wiki)