Was ist der Unterschied zwischen c beide Texte



  • @john-0

    enum
    {
         //Rückgabewerte
    }
    
    //Funktionsprototypen
    //XFunktion1: Funktion mit Anweisungen, die VOR der Schleife X ausgeführt werden müssen
    //XFunktion2: Funktion mit Anweisungen, die NACH der Schleife X ausgeführt werden müssen
    
    int MeineFunktionMit10Schleifen()
    {
         int i;
         int j;
         int k;
         int l;
         int m;
         int n;
         int o;
         int p;
         int q;
         int r;
    
         int returncode;
    
         returncode = IFunktion1();
         if(returncode == IFUNKTION1_FEHLER)
         {
         return IFUNKTION1_FEHLER;
         }
    
         for(i = 0; i < 10; i++)
         {
              returncode = JFunktion1();
              if(returncode == JFUNKTION1_FEHLER)
              {
              return JFUNKTION1_FEHLER;
              }
    
              for(j = 0; j < 10; j++)
              {
                   returncode = KFunktion1();
                   if(returncode == KFUNKTION1_FEHLER)
                   {
                        return KFUNKTION1_FEHLER;
                   }
    
                   for(k = 0; k < 10; k++)
                   {
                        returncode = LFunktion1();
                        if(returncode == LFUNKTION1_FEHLER)
                        {
                             return LFUNKTION1_FEHLER;
                        }
    
                        for(l = 0; l < 10; l++)
                        {
                             returncode = MFunktion1();
                             if(returncode == MFUNKTION1_FEHLER)
                             {
                                  return MFUNKTION1_FEHLER;
                             }
    
                             for(m = 0; m < 10; m++)
                             {
                                  returncode = NFunktion1();
                                  if(returncode == NFUNKTION1_FEHLER)
                                  {
                                       return NFUNKTION1_FEHLER;
                                  }
    
                                  for(n = 0; n < 10; n++)
                                  {
                                       returncode = OFunktion1();
                                       if(returncode == OFUNKTION1_FEHLER)
                                       {
                                            return OFUNKTION1_FEHLER;
                                       }
    
                                       for(o = 0; o < 10; o++)
                                       {
                                            returncode = PFunktion1();
                                            if(returncode == PFUNKTION1_FEHLER)
                                            {
                                                 return PFUNKTION1_FEHLER;
                                            }
    
                                            for(p = 0; p < 10; p++)
                                            {
                                                 returncode = QFunktion1();
                                                 if(returncode == QFUNKTION1_FEHLER)
                                                 {
                                                      return QFUNKTION1_FEHLER;
                                                 }
    
                                                 for(q = 0; q < 10; q++)
                                                 {
                                                      returncode = RFunktion1();
                                                      if(returncode == RFUNKTION1_FEHLER)
                                                      {
                                                           return RFUNKTION1_FEHLER;
                                                      }
    
                                                      for(r = 0; r < 10; r++)
                                                      {
                                                           returncode = RFunktionIn();
                                                           if(returncode == RFUNKTIONIN_FEHLER)
                                                           {
                                                                return RFUNKTIONI_FEHLER;
                                                           }
                                                      }
    
                                                      returncode = RFunktion2();
                                                      if(returncode == RFUNKTION2_FEHLER)
                                                      {
                                                           return RFUNKTION2_FEHLER;
                                                      }
                                                 }
    
                                                 returncode = QFunktion2();
                                                 if(returncode == QFUNKTION2_FEHLER)
                                                 {
                                                      return QFUNKTION2_FEHLER;
                                                 }
                                            }
    
                                            returncode = PFunktion2();
                                            if(returncode == PFUNKTION2_FEHLER)
                                            {
                                                 return PFUNKTION2_FEHLER;
                                            }
                                       }
    
                                       returncode = OFunktion2();
                                       if(returncode == OFUNKTION2_FEHLER)
                                       {
                                            return OFUNKTION2_FEHLER;
                                       }
                                  }
    
                                  returncode = NFunktion2();
                                  if(returncode == NFUNKTION2_FEHLER)
                                  {
                                       return NFUNKTION2_FEHLER;
                                  }
                             }
    
                             returncode = MFunktion2();
                             if(returncode == MFUNKTION2_FEHLER)
                             {
                                  return MFUNKTION2_FEHLER;
                             }
                        }
    
                        returncode = LFunktion2();
                        if(returncode == LFUNKTION2_FEHLER)
                        {
                             return LFUNKTION2_FEHLER;
                        }
                   }
    
                   returncode = KFunktion2();
                   if(returncode == KFUNKTION2_FEHLER)
                   {
                        return KFUNKTION2_FEHLER;
                   }
              }
    
              returncode = JFunktion2();
              if(returncode == JFUNKTION2_FEHLER)
              {
                   return JFUNKTION2_FEHLER;
              }
         }
    
         returncode = IFunktion2();
         if(returncode == IFUNKTION2_FEHLER)
         {
              return IFUNKTION2_FEHLER;
         }
    
         return MEINEFUNKTIONMIT10SCHLEIFEN_ERFOLG;
    }
    
    //Funktionsrümpfe
    

    Zugegeben: es ist auch ein wenig unübersichtlich, aber 10 ineinander verschachtelte Schleifen sind auch schon ziemlich extrem. Allerdings kann man am Rückgabewert der Hauptfunktion genau erkennen, wo der Fehler aufgetreten ist. Alternativ könnte man auch sowas machen:

    int MeineFunktionMit10Schleifen()
    {
         int returncode;
    
         returncode = ISchleife();
    
         return returncode;
    }
    
    int ISchleife()
    {
         int i;
    
         int returncode;
    
         //
         //Code, der vor der Schleife ausgeführt werden muss
         //
    
         for(i = 0; i < 10; i++)
         {
              returncode = JSchleife();
              if(returncode != JSCHLEIFE_ERFOLG)
              {
                   break;
              }
         }
    
         //
         //Code der nach der Schleife ausgeführt werden muss
         //
    
         return returncode;
    }
    
    //JSchleife, KSchleife etc analog
    

    beides kommt jedenfalls ohne goto aus.😉



  • @Wade1234 Das erste Snippet ist aber nicht Dein toter Ernst!? Ab spätestens 5 indentation levels in einer Funktion gilt man sogar in C als verrückt.



  • @Swordfish
    naja beim ersten kannst du relativ unkompliziert sehen, wie tief es runter geht und es sind weniger als 200 zeilen. der eigentliche code ist ja in unterfunktionen ausgelagert.



  • @Wade1234 sagte in Was ist der Unterschied zwischen c beide Texte:

    der eigentliche code ist ja in unterfunktionen ausgelagert.

    Ach so. Na dann ist ja gut. 👍🏻



  • aber mir fällt grad auf, dass im zweiten programm statt der break-anweisung auch direkt den returncode zurückgeben könnte. wäre vielleicht besser.



  • @Wade1234 Si Señor! (Aber da kommen dann wieder die Verfechter des single point of return angerannt ...)

    void foo(void) { /* ... */ };
    void bar(void) { /* ... */ };
    void qux(void)
    {
        foo();
    
        bool exit = false;  // bloeder name, ja. demonstration purpose only.
        for (/* ... */; !exit && /* ... */; /* ... */) {
            for (/* ... */; !exit && /* ... */; /* ... */) {
                if (/* something */) {
                    exit = true;
                    continue;
                }
            }
        }
    
        bar();
    }
    


  • @Swordfish sagte in Was ist der Unterschied zwischen c beide Texte:

    @Wade1234 Si Señor! (Aber da kommen dann wieder die Verfechter des single point of return angerannt ...)

    aber dann müsste ich nach der schleife wieder unterscheiden, ob da ein fehler aufgetreten ist, oder nicht, und deshalb der reguläre nach der schleife auszuführende code ausgeführt werden soll, oder nicht, und das wäre irgendwie "doof"......



  • @Wade1234 sagte in Was ist der Unterschied zwischen c beide Texte:

    das wäre irgendwie "doof"......

    weil ... ?



  • @sami12

    @Swordfish sagte in [Was ist der Unterschied zwischen c beide Texte]

    Es wäre Dir vielleicht hilfreich zu verraten, wo genau Deine Verständnisprobleme liegen.

    Die Nachfrage war ernst gemeint. Wenn Du nichts dazu sagst verliert sich dieser Thread nur in Glaubenskriegen.



  • @Swordfish

    ...ich dann doppelte fehlerüberprüfungen ausführen müsste. z.b. sowas:

         for(i = 0; i < 10; i++)
         {
              returncode = JSchleife();
              if(returncode != JSCHLEIFE_ERFOLG)
              {
                   break;
              }
         }
    
         if(returncode == JSCHLEIFE_ERFOLG)
         {
              //
              //Code der nach der Schleife ausgeführt werden muss
              //
         }
    
         return returncode;
    

    also so würde der fehler direkt nach oben durchgereicht werden:

         for(i = 0; i < 10; i++)
         {
              returncode = JSchleife();
              if(returncode != JSCHLEIFE_ERFOLG)
              {
                  //evtl: JSchleife_Fehlerbehandlung();
    
                   return returncode;
              }
         }
    
         //
         //Code der nach der Schleife ausgeführt werden muss
         //
    
         return returncode;
    


  • @Wade1234 Dann geh' mal die Assemblies vergleichen. Bringt genau nix. Code soll in erster Linie für Menschen gut lesbar geschrieben werden.



  • ist er ja (zumindest für mich) auch. wenn ein fehler auftritt, erfolgt ein sofortiger abbruch des programms, und ansonsten läuft alles ganz normal durch.



  • @Swordfish sagte in Was ist der Unterschied zwischen c beide Texte:

    Wenn Du nichts dazu sagst verliert sich dieser Thread nur in Glaubenskriegen.



  • @Swordfish sagte in Was ist der Unterschied zwischen c beide Texte:

    @john-0 Zeig ein Beispiel wo Du meinst goto zu brauchen und ich zeige Dir wie es ohne geht ^^

    Die Frage ist nicht „Wie geht es ohne goto?“ sondern „Ist der Verzicht auf goto sinnvoll?“ Ich habe jetzt nach Beispielen gesucht in Code den ich herumliegen habe, aber da der Code nicht von mir selbst ist, müsste ich ihn so kürzen, dass man den Verwendungszweck nicht mehr erkennen kann, und dann sieht man den Effekt nicht mehr. Ok, also etwas in diesem Sinne zusammenbauen. Das folgende Programm multipliziert Matrizen nach der bekannten Formel (suboptimal für größere Matrizen), und bricht die Zuweisung ab, wenn ein bestimmter Schwellwert für das Skalarprodukt der beiden Vektoren überschritten wird. So etwas ähnliches findet sich in HPC Code. Das Codebeispiel ist in Fortran, da es da eine Möglichkeit gibt, gezielt die Schleifen zu verlassen oder einen neuen Durchlauf anzustoßen.

    Update: Eine neue Programmversion, die mit der Ausgabe der C Version übereinstimmt.

    program matmultiply
        ! matmultiply.f90
        use iso_fortran_env
        implicit none
    
        integer, parameter :: s = 10
        complex(kind=real64), dimension(:,:), allocatable :: A, B, C
        complex(kind=real64) :: sl
        complex(kind=real64), parameter :: cone = cmplx(1.0_real64,0.0_real64,real64)
        integer :: i, j, k, error
        real(kind=real64) :: x, y
        character(len=256) :: message
        character(len=*), parameter :: matfmt='("("F4.2","F4.2")")'
    
        allocate(A(s,s),B(s,s),C(s,s),STAT=error,ERRMSG=message)
        if (0 /= error) then
            write(error_unit,*) message
            stop;
        end if
    
        A = cmplx(0.0_real64,0.0_real64,real64)
        B = cmplx(1.0_real64,0.0_real64,real64)
        C = cmplx(0.0_real64,0.0_real64,real64)
    
        x =  0.0_real64
        y = 10.0_real64
    
        do i=1, s
            x = x + 0.25_real64
            y = y - 1.00_real64
            A(i,i) = cmplx(x,y,real64)
        end do
    
        call write_matrix(A)
        write(output_unit,*) ''
    
        outer_loop: do i=1, s
            do j=1, s
                sl = cmplx(0.0_real64,0.0_real64,real64)
                do k=1, s
                    sl = sl + A(i,k) * B(k,j)
                end do
                if (abs(sl) > 7.0_real64) cycle outer_loop
                C(i,j) = sl
            end do
        end do outer_loop
    
        call write_matrix(C)
    contains
        subroutine write_matrix(m)
            complex(kind=real64), dimension(:,:), intent(in) :: m
    
            integer :: i, j, sm, sn
    
            sm = ubound(m,1)
            sn = ubound(m,2)
    
            do i=1, sm
                do j=1,sn
                    write(output_unit,matfmt,advance="no") m(i,j)
                end do
                write(output_unit,*) ''
            end do
        end subroutine write_matrix
    end program matmultiply
    


  • @Wade1234 sagte in Was ist der Unterschied zwischen c beide Texte:

    Zugegeben: es ist auch ein wenig unübersichtlich, aber 10 ineinander verschachtelte Schleifen sind auch schon ziemlich extrem.

    Ja, und zur zweiten Aussage - nein. Wenn man auf modernen CPUs eine simple effektive Matrizenmultiplikation machen will, muss man schon etliche Schleifen nutzen. Drei braucht man für die korrekte Umsetzung des Algorithmus, und dann muss man pro Cacheebene zwei Schleifen hinzufügen. Schau Dir das Fortran-Beispiel an, bzw. nutze goto und sehe, dass der Code deutlich kompakter und übersichtlicher wird, wenn man das anders macht.



  • @john-0 Jo, Johny, schon klar. Ich lerne jetzt mal eben auf die schnelle FORTRAN um dir eine Gegenrede in einem C-Forum geben zu können. Sag' mal, ist schon Weihnachten!?



  • @john-0 sagte in Was ist der Unterschied zwischen c beide Texte:

    gezielt die Schleifen zu verlassen oder einen neuen Durchlauf anzustoßen.

    break, continue?



  • @Wade1234 sagte in Was ist der Unterschied zwischen c beide Texte:

    @john-0 sagte in Was ist der Unterschied zwischen c beide Texte:

    gezielt die Schleifen zu verlassen oder einen neuen Durchlauf anzustoßen.

    break, continue?

    Das geht immer nur in der innersten Schleife. Man kann bei mehrfachen Schleifen in C das nicht mehr nutzen und muss auf goto zurückgreifen. Da wohl einige mit Fortran überfordert sind, das gleiche Beispiel nun in C. An dieser konkreten Stelle könne man das goto natürlich durch ein break ersetzen. Hat man aber noch ein paar Schleifen dazwischen geht das nicht mehr, und die

    #include <complex.h>
    #include <stdio.h>
    #include <stddef.h>
    #include <stdlib.h>
    
    void nop() {
        return;
    }
    
    const size_t index (const size_t i, const size_t j, const size_t row_size) {
        return i*row_size+j;
    }
    
    void init_matrix(double complex *P, const size_t m, const size_t n, const double complex value) {
        for (size_t i = 0; i < m; ++i) {
            for (size_t j = 0; j < n; ++j) {
                P[index(i,j,n)] = value;
            }
        }
    }
    
    void print_matrix(double complex* p, const size_t m, const size_t n) {
        for (size_t i = 0; i < m; ++i) {
            for (size_t j = 0; j < n; ++j) {
                printf("(%2.2f,%2.2f)",creal(p[index(i,j,n)]),cimag(p[index(i,j,n)]));
            }
            printf("\n");
        }
    }
    
    int main() {
        const size_t s = 10;
        const size_t sdc = sizeof(double complex);
        const size_t acs = sdc*sdc*s*s;
        double complex* A = 0, *B = 0 , *C = 0;
        const complex cnull = CMPLX(0.0,0.0);
        const complex cone  = CMPLX(1.0,0.0);
    
        A = malloc(acs);
        B = malloc(acs);
        C = malloc(acs);
    
        if (!A || !B || !C) return EXIT_FAILURE;
    
        init_matrix(A,s,s,cnull);
        init_matrix(B,s,s,cone);
        init_matrix(C,s,s,cnull);
    
        for (size_t i = 0; i < s; ++i) {
            B[index(i,i,s)] = cone;
        }
    
        double x =  0.0;
        double y = 10.0;
    
        for (size_t i = 0; i < s; ++i) {
            x += 0.25;
            y -= 1.00;
            A[index(i,i,s)] = CMPLX(x,y);
        }
    
        print_matrix(A,s,s);
        printf("\n");
    
        for (size_t i = 0; i < s; ++i) {
            for (size_t j = 0; j < s; ++j) {
                double complex sl = cnull;
                for (size_t k = 0; k < s; ++k) {
                    sl += A[index(i,k,s)] * B[index(k,j,s)];
                }
                if (cabs(sl) > 7.0) goto outer_loop;
                C[index(i,j,s)] = sl;
            }
            outer_loop:
            nop();
        }
    
        print_matrix(C,s,s);
    
        free(C);
        free(B);
        free(A);
    
        return EXIT_SUCCESS;
    }
    
    

    @Swordfish sagte in Was ist der Unterschied zwischen c beide Texte:

    @john-0 Jo, Johny, schon klar. Ich lerne jetzt mal eben auf die schnelle FORTRAN um dir eine Gegenrede in einem C-Forum geben zu können. Sag' mal, ist schon Weihnachten!?

    Überfordert das bisschen Code in Fortran? Sorry, aber das sollte eigentlich ohne konkrete Sprachkenntnisse nachvollziehbar sein.



  • @john-0 sagte in Was ist der Unterschied zwischen c beide Texte:

    An dieser konkreten Stelle könne man das goto natürlich durch ein break ersetzen. Hat man aber noch ein paar Schleifen dazwischen geht das nicht mehr

    break und flag oder return.

    @john-0 sagte in Was ist der Unterschied zwischen c beide Texte:

    Überfordert das bisschen Code in Fortran? Sorry, aber das sollte eigentlich ohne konkrete Sprachkenntnisse nachvollziehbar sein.

    Die Mühe mache ich mir garnicht erst. Wozu auch. Dein Hinweis das solcher code im HPC Umfeld verbreitet wäre ist lachhaft. Das geht viel besser.

    for (size_t j = 0; j < s && cabs(s1) <= 7.0; ++j) {
    

    und all Deine Probleme sind gelöst. Ohne goto.



  • @john-0 sagte in Was ist der Unterschied zwischen c beide Texte:

    Das geht immer nur in der innersten Schleife. Man kann bei mehrfachen Schleifen in C das nicht mehr nutzen und muss auf goto zurückgreifen.

    man muss kein goto benutzen, wenn man es nicht will. wenn du so riesige schleifenkonstrukte hast, solltest du die ganzen anweisungen in funktionen auslagern und ganz streng genommen, sollte man im hauptprogramm überhaupt keine direkten anweisungen haben, weil dies a) den lesefluss bzw. das verständnis sehr erheblich stört, b) die wahrscheinlichkeit relativ hoch ist, dass man diesen programmcode auch an anderer stelle brauchen könnte und c) man das programm so relativ unkompliziert verändern kann.

    ein vernünftiges hauptprogramm könnte daher so aussehen (evtl. mit besseren funktionsnamen):

    int main()
    {
         BenutzereingabeAbfragen();
         BenutzereingabeAufbereiten();
         BenutzereingabeVerarbeiten();
         ErgebnisDerVerarbeitungAusgeben();
    
         return 0;
    }
    

    wie du siehst ist das programm sehr kurz und übersichtlich, obwohl es theoretisch milliarden codezeilen in den einzelnen funktionen und deren unterfunktionen haben könnte.

    aber du siehst auf den ersten blick, was das programm macht, du kannst ganz unkompliziert eine weitere funktion einfügen oder auch eine funktion verändern, ohne dass die anderen funktionen davon betroffen sind.

    wenn du goto verwendest, ist das einfach schlechter stil. wenn die linuxentwickler goto verwenden, ist das auch schlechter stil. bei c versucht man die hauptaufgabe in verschiedene unteraufgaben zu unterteilen und diese unteraufgaben versucht man auch wieder in unteraufgaben zu unterteilen, bis es irgendwann einfach nicht mehr weiter geht, weil man ab dort bspw. auf funktionen des betriebssystems zugreifen oder inline-assembler verwenden muss oder dort die eigentlichen berechnungen ausgeführt werden sollen und dafür brauchst du schleifen, verzweigungen und funktionen, mehr nicht.


Anmelden zum Antworten