Doppelschleife verlassen - Sprungmarke vermeiden



  • nooLolo schrieb:

    fn(){
    	...
    	if (...)
    		goto out;
    	...
    	if (...)
    		goto err;
    	...
    	if (...)
    		goto out;
    	...
    err:
    	return err;
    out:
    	return ok;
    }
    

    sowas in der richtung find ich schon sauber, das hat für mich auch wenig mit spagetti code zu tun, goto ist ein normales statement, und wenn man damit etwas schön machen kann wie z.b. aus einer verschachtelten schleife raus springen, dann muß man sich auch nicht verbiegen es anders zu machen nur um kein goto zu verwenden...

    aber da hat ja jeder so seine meinung 😉

    lg lolo

    Genau sowas ist ziemlich grauenvoll. Einen Sprung einzubauen, am Besten noch über mehrere Bildschirmseiten hinweg, nur um an der Sprungmarke einen Wert zurückzugeben ist unübersichtlich. Dann lieber gleich an der Stelle des goto ein return. Wir sind nicht mehr im letzten Jahrtausend wo noch single-entry-single-exit gepredigt wurde.



  • hustbaer schrieb:

    Na dann frag deine(n) Prof wie er/sie das machen würde.
    Idealerweise mit einem Beispiel das sich nicht einfach auf "return" umbauen lässt.

    p.S.: natürlich lässt sich alles mit mehr oder weniger Aufwand auf "return" umbauen, z.B. mit Hilfe des Method-Object Patterns. Nur ist das in einigen Fällen wohl Overkill.

    p.p.S.: in der Praxis ist mir allerdings in den letzten Jahren kein Fall mehr untergekommen, wo ich wirklich noch "goto" verwendet habe. Auch kein Fall wo ich einen hässlichen Workaround verwendet hätte um "goto" zu vermeiden. Sogesehen muss ich fast sagen: es *scheint* zumindest immer eine "ausreichend elegante" Alternative zu "goto" zu geben.

    Wie du schon sagst, es gibt wohl immer ne Möglichkeit, das ganze ohne goto zu machen. Bloß wirds dadurch vielleicht manchmal sogar komplizierter als nötig. Man erkennt evtl hinterher gar nicht mehr sofort, was der Algorithmus macht. Ich finde meine goto-Lösung oben noch recht "human", denn wie gesagt, die Marke zu der er springt, befindet sich gleich unterhalb der Schleifen. Die Lösung, die Nexus gepostet hat, ist auch nicht übel. Aber da muss ich erst den Code an anderer Stelle wieder bissl umbauen.
    Ich habe im Netz gestern noch einen guten Artikel von Donald Knuth gefunden, in dem es um die Nützlichkeit von goto-Befehlen geht. Da steht auch drin, dass es Situationen gibt, in denen eine Sprungmarke einfach eleganter, besser und effizienter ist. Doch an meiner Uni herrscht leider nur die gegenteilige Meinung. Sobald da goto irgendwo auftaucht oder man nur davon redet....wird man gesteinigt. 😞



  • Und warum nicht mit zwei do-while Schleifen?

    Beide bekommen in der Abbruchbedingung zusätzlich zur Arraygrenze eine boolsche Variable.

    Wenn du deine Zahl findest, setzt du die Variable true und sie wird sofort in der nächsten Iteration ausgewertet.

    Hat halt den Vorteil, dass du keine Sprünge brauchst und nicht mit return aus der Funktion raus musst. Du wärst damit halt flexibler.



  • DarthZiu schrieb:

    Beide bekommen in der Abbruchbedingung zusätzlich zur Arraygrenze eine boolsche Variable.

    von hinten durch die brust ins auge...
    abgesehen davon, das durch die 2 flags dein code langsamer wird macht es das doch sicher nicht einfacher oder?

    DarthZiu schrieb:

    Hat halt den Vorteil, dass du keine Sprünge brauchst und nicht mit return aus der Funktion raus musst. Du wärst damit halt flexibler.

    ein programm das nicht spring ist kein programm, was macht ein "return" "break" "continue" "if" "switch" "for" "while" oder eine einfacher functionsaufruf? alle springen nur das hübsche "goto" darf nicht mit machen, also ich find das bischen übertrieben...

    aber ja es stimmt man kann es sich auch immer anders hin bauen z.b.

    if(i==1){
    
    }else{
    
    }
    
    oder 
    switch(i){
      case 1:
    
      break;
      default:
    
      break;
    }
    

    *ironie*

    lg lolo



  • @Euler:
    Ja in der Theorie gibt es Fälle wo "goto" auch in C++ angebracht scheint (C ist da sowieso was anderes, da keine Destruktoren etc., da braucht man öfters goto).
    In der Praxis ... wie schon gesagt ... hatte ich sowas in den letzten Jahren nicht mehr.

    Und ich würde sagen dass ich ohne "goto" keinen komplizierteren Code schreibt als mit. Ganz im Gegenteil: ohne "goto" wird der Code meist sauberer. Natürlich nur wenn man es richtig macht, und nicht so seltsame Dinge macht wie DarthZiu vorgeschlagen hat.

    @DarthZiu:
    Solche unnötigen Variablen machen ein Programm erst recht schwer zu lesen, schwer nachzuvollziehen wie es funktioniert bzw. zu checken ob alle möglichen Fälle abgedeckt sind.

    @ALL:
    Interessant wäre ein konkretes Beispiel wo goto angebracht scheint um eine innere Schleife zu verlassen. Dann könnte jeder "seine" Version dieses Codes posten (mit goto, mit Hilfsvariablen, mit return), dann hätte man etwas was man wirklich vergleichen kann.



  • [quote="noobLolo"]
    von hinten durch die brust ins auge...
    abgesehen davon, das durch die 2 flags dein code langsamer wird macht es das doch sicher nicht einfacher oder?
    [/qoute]

    Du willst mir aber nicht erzählen, dass das bei einem modernen Prozessor einen spürbaren Unterschied gibt? Wenn wir hier von Arrays > 100.000 Elementen sprechen würden, oder von einem langsamen Prozessor, könnte ich deinen Einwand verstehen.

    noobLolo schrieb:

    ein programm das nicht spring ist kein programm, was macht ein "return" "break" "continue" "if" "switch" "for" "while" oder eine einfacher functionsaufruf? alle springen nur das hübsche "goto" darf nicht mit machen, also ich find das bischen übertrieben...

    Tja, dann solltest du vielleicht ein wenig Erfahrung in der Wirtschaft sammeln. In meinem derzeitigen Job arbeite ich mit mehreren hundert Entwicklern an einem System, dass mehr als 7 Mio Zeilen Code hat. Wenn hier jeder anfangen würde wilde goto's einzubauen, dann würde man bald gar nicht mehr durchblicken.

    Es ist ja mit dem einen goto nicht getan, weil du nach der Doppelschleife entweder über den goto-Block mit einem weiteren goto springen musst, oder halt zwei return-Zweige brauchst.

    In den SW-Firmen, in denen ich bisher gearbeitet habe, sind aus gutem Grund goto's und continue's im Coding Guide verboten. Und break ist nur in switch-case-Strukturen erlaubt. Warum denkt ihr denn, dass diese Sprünge bei Prof's verpöhnt sind? Weil die wissen, was aus solchem Wildwuchs in der Realität wird.

    Sicher gibt es Stellen, wo man aufgrund der Performance solche Konstrukte braucht, aber man sollte sie selten und bewusst und gut kommentiert einsetzen.

    Beim Thema C auf µC ist das natürlich ne andere Geschichte.



  • DarthZiu schrieb:

    Du willst mir aber nicht erzählen, dass das bei einem modernen Prozessor einen spürbaren Unterschied gibt? Wenn wir hier von Arrays > 100.000 Elementen sprechen würden, oder von einem langsamen Prozessor, könnte ich deinen Einwand verstehen.

    ach das summiert sich eben auf, und es muß nicht unbedingt schnell sondern sauber sein.

    DarthZiu schrieb:

    Tja, dann solltest du vielleicht ein wenig Erfahrung in der Wirtschaft sammeln. In meinem derzeitigen Job arbeite ich mit mehreren hundert Entwicklern an einem System, dass mehr als 7 Mio Zeilen Code hat. Wenn hier jeder anfangen würde wilde goto's einzubauen, dann würde man bald gar nicht mehr durchblicken.

    ja da hast du mir evtl. etwas voraus, ich habs bisher mit meinen kentnissen in noch keine firma geschafft und tippsel daheim so vor mich hin, daher ist auch der einzige (meißte) code den ich mir anschauen kann opensource

    der linux kern ist voll von gotos, und weil mich rüdiger gestern in einer diskussion auf die strstr() implementation der glibc gestoßen hat post ich mal nen auszug

    /*
     * My personal strstr() implementation that beats most other algorithms.
     * Until someone tells me otherwise, I assume that this is the
     * fastest implementation of strstr() in C.
     * I deliberately chose not to comment it.  You should have at least
     * as much fun trying to understand it, as I had to write it :-).
     *
     * Stephen R. van den Berg, berg@pool.informatik.rwth-aachen.de */
    
    #if HAVE_CONFIG_H
    # include <config.h>
    #endif
    
    #if defined _LIBC || defined HAVE_STRING_H
    # include <string.h>
    #endif
    
    typedef unsigned chartype;
    
    #undef strstr
    
    char *
    strstr (phaystack, pneedle)
         const char *phaystack;
         const char *pneedle;
    {
      const unsigned char *haystack, *needle;
      chartype b;
      const unsigned char *rneedle;
    
      haystack = (const unsigned char *) phaystack;
    
      if ((b = *(needle = (const unsigned char *) pneedle)))
        {
          chartype c;
          haystack--;               /* possible ANSI violation */
    
          {
            chartype a;
            do
              if (!(a = *++haystack))
                goto ret0;
            while (a != b);
          }
    
          if (!(c = *++needle))
            goto foundneedle;
          ++needle;
          goto jin;
    
          for (;;)
            {
              {
                chartype a;
                if (0)
                jin:{
                    if ((a = *++haystack) == c)
                      goto crest;
                  }
                else
                  a = *++haystack;
                do
                  {
                    for (; a != b; a = *++haystack)
                      {
                        if (!a)
                          goto ret0;
                        if ((a = *++haystack) == b)
                          break;
                        if (!a)
                          goto ret0;
                      }
                  }
                while ((a = *++haystack) != c);
              }
            crest:
              {
                chartype a;
                {
                  const unsigned char *rhaystack;
                  if (*(rhaystack = haystack-- + 1) == (a = *(rneedle = needle)))
                    do
                      {
                        if (!a)
                          goto foundneedle;
                        if (*++rhaystack != (a = *++needle))
                          break;
                        if (!a)
                          goto foundneedle;
                      }
                    while (*++rhaystack == (a = *++needle));
                  needle = rneedle; /* took the register-poor aproach */
                }
                if (!a)
                  break;
              }
            }
        }
    foundneedle:
      return (char *) haystack;
    ret0:
      return 0;
    }
    libc_hidden_builtin_def (strstr)
    

    und weils gar so schön ist noch ein kleiner auszug aus dem linux kernel

    int vfs_readdir(struct file *file, filldir_t filler, void *buf)
    {
    	struct inode *inode = file->f_path.dentry->d_inode;
    	int res = -ENOTDIR;
    	if (!file->f_op || !file->f_op->readdir)
    		goto out;
    
    	res = security_file_permission(file, MAY_READ);
    	if (res)
    		goto out;
    
    	res = mutex_lock_killable(&inode->i_mutex);
    	if (res)
    		goto out;
    
    	res = -ENOENT;
    	if (!IS_DEADDIR(inode)) {
    		res = file->f_op->readdir(file, buf, filler);
    		file_accessed(file);
    	}
    	mutex_unlock(&inode->i_mutex);
    out:
    	return res;
    }
    

    ich denke das ist auch große software und da arbeiten ne ganze menge leute > 1000 dran die nochmal ein ganzes stückchen klüger sind als ich, ich hab zwar keinen plan warum die das so machen geschweige denn das ich verstehe was die da treiben, aber die werden schon wissen was sie machen...

    sonst würd das zeug ja nicht in dem umfang verwendet 😉

    lg lolo



  • Der Linux-Kernel und die Implementierung der Standard-Librarys fallen definitiv unter:

    DarthZiu schrieb:

    Sicher gibt es Stellen, wo man aufgrund der Performance solche Konstrukte braucht, aber man sollte sie selten und bewusst und gut kommentiert einsetzen.



  • @DarthZiu:
    du kannst mir doch nicht erzählen das die paar gotos aus der 'vfs_readdir()' unübersichtlich sind?

    die strstr() wird so wie ich das sehe für längere zeit nicht verändert, und wenn doch dann entweder von dem der sie gebaut hat, oder komplett neu gemacht.

    gotos sind doch eh nur innerhalb der function gültig, da die eh nicht so lang sein sollen ist das doch null problemo?

    naja denke das wird eine endlose diskussion die kein ende findet weil keiner nachgibt, mir ist es gleich wenn einer ein goto verwendet, da find ich jede globale variable schlimmer aber naja ich kann auch deine meinung verstehen, und natürlich geht auch 99% ohne goto, aber es ist nun mal ein teil der sprache und das zu verbieten ist als würd ich dir den kleinen finger abschneiden, denn den verwendest eh in 99% der fälle nicht^^

    lg lolo


  • Mod

    noobLolo schrieb:

    * Until someone tells me otherwise, I assume that this is the
     * fastest implementation of strstr() in C.
    

    ich denke das ist auch große software und da arbeiten ne ganze menge leute > 1000 dran die nochmal ein ganzes stückchen klüger sind als ich, ich hab zwar keinen plan warum die das so machen geschweige denn das ich verstehe was die da treiben, aber die werden schon wissen was sie machen...

    Für meinen Geschmack zuviele Annahmen...



  • Warum streitet ihr euch eigentlich in einem C++-Forum über alte Denkschulen der Fehlerbehandlung in C? Es steht doch außer Frage, dass kein C++-Programmierer mit mehr als zwei Wochen Erfahrung (sprich, der schonmal was von Exceptions gehört hat) vfs_readdir so aufbauen würde.

    Und zu dieser strstr-Implementation verliere ich besser kein Wort.



  • noobLolo schrieb:

    und weils gar so schön ist noch ein kleiner auszug aus dem linux kernel

    int vfs_readdir(struct file *file, filldir_t filler, void *buf)
    {
    	struct inode *inode = file->f_path.dentry->d_inode;
    	int res = -ENOTDIR;
    	if (!file->f_op || !file->f_op->readdir)
    		goto out;
    
    	res = security_file_permission(file, MAY_READ);
    	if (res)
    		goto out;
    
    	res = mutex_lock_killable(&inode->i_mutex);
    	if (res)
    		goto out;
    
    	res = -ENOENT;
    	if (!IS_DEADDIR(inode)) {
    		res = file->f_op->readdir(file, buf, filler);
    		file_accessed(file);
    	}
    	mutex_unlock(&inode->i_mutex);
    out:
    	return res;
    }
    

    Was soll n der Quatsch? Ein goto, das zu nem return spring. Wieso nicht gleich return res?



  • Weil der Compiler Funktionen mit nur einem return Wert besser optimieren kann



  • dfgdhdh schrieb:

    Weil der Compiler Funktionen mit nur einem return Wert besser optimieren kann

    Ich bezweifle, dass das ein Unterschied für dem Compiler macht, ob nun eine Sprunganweisung in Form eines goto da steht oder in Form von einem direktem return.


  • Administrator

    dfgdhdh schrieb:

    Weil der Compiler Funktionen mit nur einem return Wert besser optimieren kann

    Und goto kann er natürlich so unglaublich gut optimieren 😃

    Grüssli



  • seldon schrieb:

    Warum streitet ihr euch eigentlich in einem C++-Forum über alte Denkschulen der Fehlerbehandlung in C? Es steht doch außer Frage, dass kein C++-Programmierer mit mehr als zwei Wochen Erfahrung (sprich, der schonmal was von Exceptions gehört hat) vfs_readdir so aufbauen würde.

    Und zu dieser strstr-Implementation verliere ich besser kein Wort.

    ich dachte es ging unm "goto" und nicht die Fehlerbehandlung in C

    lg lolo



  • seldon schrieb:

    Es steht doch außer Frage, dass kein C++-Programmierer mit mehr als zwei Wochen Erfahrung (sprich, der schonmal was von Exceptions gehört hat) vfs_readdir so aufbauen würde.

    Mit C++ Exceptions sollte man sehr sparsam sein.
    http://msdn.microsoft.com/en-us/library/c0hwkhwe(VS.80).aspx



  • C++Fan 2010 schrieb:

    seldon schrieb:

    Es steht doch außer Frage, dass kein C++-Programmierer mit mehr als zwei Wochen Erfahrung (sprich, der schonmal was von Exceptions gehört hat) vfs_readdir so aufbauen würde.

    Mit C++ Exceptions sollte man sehr sparsam sein.
    http://msdn.microsoft.com/en-us/library/c0hwkhwe(VS.80).aspx

    blah
    blaaaaaaaaaaaaaaaaaaaaaaaah

    6, setzen



  • also hustbaer, beweise belege, erfahrungen o.ä. blah bringt uns alle nicht weiter 😉

    evtl. erninnere ich mal an das thread thema "Doppelschleife verlassen - Sprungmarke vermeiden"
    und nicht "C++ Exceptions"

    lg lolo



  • hustbaer schrieb:

    blah
    blaaaaaaaaaaaaaaaaaaaaaaaah

    Du wolltest mir was mitteilen?


Anmelden zum Antworten