Sinnvolle Formatierung vieler geschachtelter Kontrollstrukturen



  • Hallo

    Ich habe es immer wieder mit mehreren verschachtelten Schleifen zu tun, z.B. drei verschachtelte for-schleifen mit if-Schleife sowie auch switch darin.

    Inzwischen verstehe ich diese Kontrollschleifen ganz gut, aber mit lesbarer Formatierung tue ich mir noch sehr schwer. Ich habe gesehen, in Literatur und dem Web, dass die Leute die C++ deutlich besser beherrschen als ich, bei solchen Situationen mit Texteinrückungen arbeiten.

    Würde mir bitte jemand sagen, wie man allgemein am besten solchen Code formatieren soll?

    Ist es ein guter Ansatz die äußerste Schleife ohne Einrückung zu schreiben und dann jede innere ein wenig nach rechts versetzt oder geht es besser?

    Danke und Grüße
    cpp_Jungspund



  • Einrücken ist auf jeden Fall schonmal ein guter Ansatz. Eine weitere Methode wäre, Strukturen in Hilfsfunktionen auszulagern. Poste doch mal ein Beispiel, daran lässt sich besser diskutieren.



  • Im allgemeinen rückt man seinen Code bei jeder öffnenen { Klammer ein Stück nach rechts ein und bei jeder schließenden } Klammer wieder nach links. Je nach Programmcode kann es hier zu sehr tiefen Einrückungsebenen führen was die Lesbarkeit auch wieder negativ beeinflusst. Da sollte man sich überlegen ob man seinen Code nicht etwas umstrukturieren kann oder Teile in Funktionen auslagert. Ich bin mittlerweile dazu übergegeben bei 3 verschachtelten Schleifen nur die innere einzurücken:

    for(int z = 0; z < Lz; ++z)
    for(int y = 0; y < Ly; ++y)
    for(int x = 0; x < Lx; ++x)
    {
      // Do something
    }
    

    Finde ich wesentlich lesbarer als

    for(int z = 0; z < Lz; ++z)
    {
      for(int y = 0; y < Ly; ++y)
      {
        for(int x = 0; x < Lx; ++x)
        {
          // Do something
        }
      }
    }
    

    Mache ich aber auch nur wenn die äußeren beiden Schleifen keinen Code haben.



  • cpp_Jungspund schrieb:

    Ich habe es immer wieder mit mehreren verschachtelten Schleifen zu tun, z.B. drei verschachtelte for-schleifen ..

    Hallo cpp_Jungspund,

    besser ist es, das Programm so zu gestalten, dass es dazu gar nicht kommt. 'Strukturen in Hilfsfunktionen auslagern' ist zunächst mal ein guter Hinweis.
    Noch besser ist es, sich über den grundlegenden Aufbau und das Design seines Programms Gedanken zu machen.

    Beispiel: Ich arbeite z.Zt. an einem Projekt mit ca. 400000 Zeilen Code und mehr als 15000 Dateien. Es gibt praktisch keine Datei die mehr als zwei verschachtelte Schleifen enthält (if nicht mitgerechnet). Und wenn es mehr Verschachtelungen mit if und for(bzw. while) gibt, dann bestehen die inneren Schleifen oder if-Statements aus einer bis drei Zeilen - sind also durchaus übersichtlich.

    Dieses Code-Bild

    for( .. ) {  // oder while oder if
            for( .. ) {
                for( .. )  {
                    // und hier viele Zeilen Code
                }
            }
        }
    } // Ende der Funktion
    

    weißt auf ein ungünstiges Design hin.

    Gruß
    Werner



  • - Öffnende und schließende Klammern vertikal übereinander.
    - Einrückung um vier bzw. zwei Spalten.

    Ansonsten: Funktionen schaffen, Design überdenken.

    Das sollte helfen.



  • Werner Salomon schrieb:

    Dieses Code-Bild

    for( .. ) {  // oder while oder if
            for( .. ) {
                for( .. )  {
                    // und hier viele Zeilen Code
                }
            }
        }
    } // Ende der Funktion
    

    weißt auf ein ungünstiges Design hin.

    Finde ich gar nicht mal. Solange die äußeren beiden Schleifen keinen Code enthalten zählt das für mich nur als eine Schleifen. Ist dann einfach nur eine Schleife über alle Elemente einer verschachtelten Datenstruktur. Wenn auf den verschiedenen Ebenen aber auch noch verstreuter Code steht stimme ich dir zu.



  • Erstmal Danke für die Beiträge.

    Hier mal eine typische while Schleife aus einem Programm von mir:

    while(ncounter_bip<MAX_VAR_MUSTER){
    
    for (ik=0;ik<ADSIZE;++ik) 
    {
       hilfsneuronen_bip[ik]=0;
       for (il=0;il<ADSIZE;++il) {                         
       hilfsneuronen_bip[ik]=hilfsneuronen_bip[ik]+adjazenz_bip[ik][il]*neuronen_bip[il];} //Update Regel   
    
       if (hilfsneuronen_bip[ik]>threshold) {hilfsneuronen_bip[ik]=1;}             //Treshold                                  
       else hilfsneuronen_bip[ik]=0;
    }
    
    for (ik=0;ik<ADSIZE;++ik) {neuronen_bip[ik]=hilfsneuronen_bip[ik];}
    
    nzahl_bip=0;
    for(ik=0;ik<ADSIZE;++ik){nzahl_bip=nzahl_bip + neuronen_bip[ik]*pow(2,ik);}//Neuronale Aktivität -> Zahl
    
    if(Basins_bip[nzahl_bip]==0){Basins_bip[nzahl_bip]=nattractor_bip;}
    
    else{if(Basins_bip[nzahl_bip]==nattractor_bip)
    {
       nattractor_bip=nattractor_bip+1;
       while(Basins_bip[ncounter_bip]>0){ncounter_bip=ncounter_bip+1;}
       ih1_bip=ncounter_bip;
       Basins_bip[ncounter_bip]=nattractor_bip;
       for(ik=0;ik<ADSIZE;++ik){neuronen_bip[ik]=ih1_bip%2; ih1_bip=(ih1_bip-neuronen_bip[ik])/2;}//Zahl -> Neuronale Aktivität
    }
    
    else{
       in=0;
       for(ik=0;ik<MAX_VAR_MUSTER;++ik){
       if(Basins_bip[ik]==nattractor_bip){
       in=in+1;
       Basins_bip[ik]=Basins_bip[nzahl_bip];}}
    
       while(Basins_bip[ncounter_bip]>0){
       ncounter_bip=ncounter_bip+1;
       in=in+1;}
    
       Basins_bip[ncounter_bip]=nattractor_bip;
       if(nattractor_bip>100){
       cout << "Warnung: Attraktor > 100";
       exit(EXIT_FAILURE);}
    
       ih1_bip=ncounter_bip;
    
       for(ik=0;ik<ADSIZE;++ik){neuronen_bip[ik]=ih1_bip%2; ih1_bip=(ih1_bip-neuronen_bip[ik])/2;}
      }
     }
    }
    

    Frage mich wie man das nun besser formatiert.

    Lieben Gruß
    cpp_Jungspund



  • Benutze Leerzeichen!



  • 1. Einrücken
    2. Nicht so viel in eine Zeile packen
    3. Egal welchen Style du hast, immer einheitlich bleibem, ganz wichtig!

    Beispiel:

    while(ncounter_bip < MAX_VAR_MUSTER) { 
    	for (ik=0; ik<ADSIZE; ++ik) { 
    		hilfsneuronen_bip[ik] = 0; 
    		for (il=0; il<ADSIZE; ++il) {                         
    			hilfsneuronen_bip[ik] = hilfsneuronen_bip[ik] + adjazenz_bip[ik][il] * neuronen_bip[il];
    		} //Update Regel   
    
    		if (hilfsneuronen_bip[ik] > threshold)  //Treshold 
    			hilfsneuronen_bip[ik] = 1;                                              
    		else 
    			hilfsneuronen_bip[ik] = 0; 
    	}
    
    	for (ik=0; ik<ADSIZE; ++ik) {
    		neuronen_bip[ik] = hilfsneuronen_bip[ik];
    	} 
    
    	nzahl_bip = 0; 
    	for(ik=0; ik<ADSIZE; ++ik) {
    		nzahl_bip = nzahl_bip + neuronen_bip[ik] * pow(2, ik); //Neuronale Aktivität -> Zahl 
    	}
    
    	if(Basins_bip[nzahl_bip] == 0) {
    		Basins_bip[nzahl_bip] = nattractor_bip;
    	} else {
    		if(Basins_bip[nzahl_bip] == nattractor_bip) { 
    			nattractor_bip = nattractor_bip + 1; 
    			while(Basins_bip[ncounter_bip] > 0) {
    				ncounter_bip = ncounter_bip+1;
    			} 
    			ih1_bip = ncounter_bip; 
    			Basins_bip[ncounter_bip] = nattractor_bip; 
    			for(ik=0; ik<ADSIZE; ++ik) {
    				neuronen_bip[ik] = ih1_bip % 2;
    				ih1_bip = (ih1_bip - neuronen_bip[ik]) / 2; //Zahl -> Neuronale Aktivität
    			}
    		} else { 
    			in = 0; 
    			for(ik=0; ik<MAX_VAR_MUSTER; ++ik) { 
    				if(Basins_bip[ik] == nattractor_bip) { 
    					in = in + 1; 
    					Basins_bip[ik] = Basins_bip[nzahl_bip];
    				}
    			} 
    
    			while(Basins_bip[ncounter_bip] > 0) { 
    				ncounter_bip = ncounter_bip + 1; 
    				in = in + 1;
    			} 
    
    			Basins_bip[ncounter_bip] = nattractor_bip; 
    			if(nattractor_bip > 100) { 
    				cout << "Warnung: Attraktor > 100"; 
    				exit(EXIT_FAILURE);
    			} 
    
    			ih1_bip = ncounter_bip; 
    
    			for(ik=0; ik<ADSIZE; ++ik) {
    				neuronen_bip[ik] = ih1_bip % 2;
    				ih1_bip = (ih1_bip - neuronen_bip[ik]) / 2;
    			} 
    		}
    	}
    }
    


  • Schau Dir die Header <algorithm> und <numeric> an.

    Danach entwickel einen gewissen Spass daran, die Dinger anzuwenden...
    fill() accumulate(), transform(), generate(), copy() Meist geht dabei eine explizite for()-Schleife flöten.

    Nutz das Range-based-for aus C++11. for(auto& a : arr)... .

    Ich habe mir dummerweise die erste Schleife rausgesucht und nach fertigen Algorithmen geschaut um die umzusetzen.
    Das klappt auch...allerdings geht die Leserlichkeit flöten 🙂

    for (ik=0; ik<ADSIZE; ++ik) {
            hilfsneuronen_bip[ik] = 0;
            for (il=0; il<ADSIZE; ++il) {                        
                hilfsneuronen_bip[ik] = hilfsneuronen_bip[ik] + adjazenz_bip[ik][il] * neuronen_bip[il];
            } //Update Regel  
    
            if (hilfsneuronen_bip[ik] > threshold)  //Treshold
                hilfsneuronen_bip[ik] = 1;                                              
            else
                hilfsneuronen_bip[ik] = 0;
        }
    

    ➡

    // angenommen: double adjazenz_bip[ADSIZE][ADSIZE] und double hilfsneuronen[ADSIZE]
    // geht sicher auch generisch mit decltype()...o.ae.
    transform(begin(adjazenz_bip), end(adjazenz_bip), begin(hilfsneuronen), [=](double (&adj)[ADSIZE]){
          return inner_product(begin(adj), end(adj), begin(neuronen_bip), 0)>threshold?1:0;
        });
    

    Hoffentlich habe ich mich nicht vertan... 😉



  • Funktionen verwenden.
    Richtwert: nicht mehr als 10 Zeilen pro Funktion.

    Die meisten Funktionen haben unter 6 Zeilen!



  • Shade Of Mine schrieb:

    Funktionen verwenden.
    Richtwert: nicht mehr als 10 Zeilen pro Funktion.

    Die meisten Funktionen haben unter 6 Zeilen!

    Das geht bei mir höchstens im Arithmetischen Mittel auf.
    Man kann es auch übertreiben...

    EDIT: außerdem:

    for 
    {
     //...
    }
    

    vs

    for {
    }
    

    oder gar

    for () { /* ... */}
    

    Ich halte von solchen über den Daumen gebrochenen Sachen nichts.



  • Shade Of Mine schrieb:

    Funktionen verwenden.
    Richtwert: nicht mehr als 10 Zeilen pro Funktion.

    Die meisten Funktionen haben unter 6 Zeilen!

    Im letzten Jahrtausend galt noch irgendwas mit "nicht mehr als auf den Bildschirm paßt".
    Und der hatte aber schon (min) 25 Zeilen.



  • DirkB schrieb:

    Im letzten Jahrtausend galt noch irgendwas mit "nicht mehr als auf den Bildschirm paßt".
    Und der hatte aber schon (min) 25 Zeilen.

    Nein, diese waren 80x24 und hatten dementsprechend 24 Zeilen.



  • Ein C64 hatte ja sogar schon 25 Zeilen. Und wenn jetzt einer kommt mit, aber nur 40 Zeichen pro Zeile: der C128 hatte dann ein 80*25 Zeilen Modus und sogar einen 80*50 Modus.



  • Einfach den Breitbildmonitor hochkant aufstellen. Und schon gelten andere Maßstäbe.



  • Da war der Finger zu schnell..
    Wollte eigentlich noch sagen: Such einfach mal nach "c++ Style(s)", und nimm den, der dir am besten gefällt..



  • Die Vielfalt der Antworten und Ratschläge zeigt, dass man hier seinen eigenen Style finden und festhalten sollte. 😉



  • Das sieht wirklich grässlich aus. Ein wichtiger Tipp ist, viel mehr Leerraum zu lassen. Ich versuche mal den Code ein wenig lesbarer zu formatieren:

    while (ncounter_bip < MAX_VAR_MUSTER)
    {
        for (ik = 0; ik < ADSIZE; ++ik)
        {
            hilfsneuronen_bip[ik] = 0;
    
            for (il=0; il < ADSIZE; ++il)
                hilfsneuronen_bip[ik] = hilfsneuronen_bip[ik]
                                      + adjazenz_bip[ik][il] * neuronen_bip[il]; // Update Regel
    
            if (hilfsneuronen_bip[ik] > threshold)
                hilfsneuronen_bip[ik] = 1;       // Treshold
            else
                hilfsneuronen_bip[ik] = 0;
        }
    
        for (ik=0; ik < ADSIZE; ++ik)
            neuronen_bip[ik] = hilfsneuronen_bip[ik];
    
        nzahl_bip = 0;
        for (ik=0; ik<ADSIZE; ++ik)
            nzahl_bip = nzahl_bip + neuronen_bip[ik] * pow(2, ik);   // Neuronale Aktivität -> Zahl
    
        if (Basins_bip[nzahl_bip] == 0)
        {
            Basins_bip[nzahl_bip] = nattractor_bip;
        }
        else if (Basins_bip[nzahl_bip] == nattractor_bip)
        {
            nattractor_bip = nattractor_bip + 1;
            while (Basins_bip[ncounter_bip] > 0)
                ncounter_bip = ncounter_bip + 1;
    
            ih1_bip = ncounter_bip;
            Basins_bip[ncounter_bip] = nattractor_bip;
    
            for (ik=0; ik<ADSIZE; ++ik)
            {
                neuronen_bip[ik] = ih1_bip % 2;
                ih1_bip = (ih1_bip - neuronen_bip[ik]) / 2;  // Zahl -> Neuronale Aktivität
            }
        }
        else
        {
            in = 0;
            for (ik=0; ik < MAX_VAR_MUSTER; ++ik)
            {
                if (Basins_bip[ik] == nattractor_bip)
                {
                    in = in + 1;
                    Basins_bip[ik] = Basins_bip[nzahl_bip];
                }
            }
    
            while (Basins_bip[ncounter_bip] > 0)
            {
                ncounter_bip = ncounter_bip + 1;
                in = in + 1;
            }
    
            Basins_bip[ncounter_bip] = nattractor_bip;
    
            if (nattractor_bip > 100)
            {
                cout << "Warnung: Attraktor > 100";
                exit(EXIT_FAILURE);
            }
    
            ih1_bip = ncounter_bip;
    
            for (ik=0; ik < ADSIZE; ++ik)
            {
                neuronen_bip[ik] = ih1_bip % 2;
                ih1_bip = (ih1_bip - neuronen_bip[ik]) / 2;
            }
      }
    }
    

    Ein Paar Regeln, die ich hier verwendet habe:

    • um jeden Operator Leerzeichen
    • ein Statement pro Zeile
    • Bei Kontrollstrukturen vor der Klammer ein Leerzeichen ( while (...) )
    • Jede geschweifte Klammer bekommt eine eigene Zeile
    • Leerzeilen zwsichen Kontrollstrukturen und auch sonst nicht mit Leerzeilen geizen
    • Einheitlich einrücken (eigentlich komisch, dass man das überhaupt erwähnen muss, aber leider sehe ich oft code, wo selbst die Einrückung nicht stimmt)
    • Prinzipiell ist der Hinweis, Probleme in Funktionen auszulagern immer gut, so dass das Unterproblem auch einen Namen bekommt.
    • Eine Regel, die ich hier nicht verwendet habe, aber ich noch empfehle ist die einheitliche Benennung von Variablen, also z.B. immer mit Kleinbuchstaben anfangen (siehe Dein nattractor_bip vs. Basins_bip )

    Es gibt viele Stile. Ich habe meinen Stil, bin aber gerne bereit, mich dem Team, in dem ich arbeite anzupassen. Ich finde ein einheitlicher Stil im Team ist wichtiger als mein eigener.



  • Noch ein Hinweis von mir: Wenn es geht kombinierte Operatoren +=, -=, usw. und ++, -- verwenden.
    Bei Zeilen wie

    ncounter_bip = ncounter_bip + 1;
    

    muss ich mehrmals hin und her gucken ob beides wirklich die gleichen Variablen sind oder ob die sich nicht doch in einem Zeichen unterscheiden. Bei

    ++ncounter_bip;
    

    ist mir sofort klar was passiert.

    Andere Stelle:

    hilfsneuronen_bip[ik] = 0;
    for (il=0; il < ADSIZE; ++il)
        hilfsneuronen_bip[ik] = hilfsneuronen_bip[ik]
                              + adjazenz_bip[ik][il] * neuronen_bip[il]; // Update Regel
    

    könnte man += verwenden. Dadurch wird die Zeile auch deutlich kürzer weil man den langen Variablennamen nicht zweimal nennen muss.


Log in to reply