www.mikrocontroller.net

Forum: PC-Programmierung Sprung zu MAIN in C


Autor: Carolin Zapa (seobalis)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute,
ich habe ein Problem mit der direkte Sprung in C. Ich habe noch nicht 
viel Ahnung wie das am besten laufen soll. Oder mir fehlt es noch die 
Verständnis :(

#include<stdio.h>
int main(){
  for(..){
    if(...)
       unterprogramm1();
    if(...)
       unterprogramm2();
    label: printf("...");

  }
return 0;
}
void unterprogramm1(){
  if(..)
    goto label;
  else ..
}

void unterprogramm2(){
  if(..)
    goto label;
  else ...
}


So habe ich mir das gedacht. Aber der scheint nicht zu funktionieren.
Ich bedanke mich für euere Hilfe.

Carolin

Autor: foo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Goto gilt nur im selben Block wie das Label zu dem du springen
willst. Sprich { .... label: ... goto label} ist okay,
aber {.... label: .... } .... {... goto label...} geht nicht.

Aus nem andern Block geht mit setjmp und longjmp.

Goto und longjmp erst recht sollte man nur benutzen
wenn man wirklich "weiss was man tut". Es gibt Anwendungsfälle
wo es sinnvoll ist, zb gemeinsame Fehlersprungstellen. (der linux
Kern ist voll davon).

Ansonsten: Lass die Finger davon, macht das Programm sonst
absolut unleserlich/wartbar.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
kommst aus der Basic Ecke?
Spaghetti-Code gibts nicht mehr. Labels auch nicht.
Anstatt "goto" schreibtst du einfach "return".
Das Programm wird dann an der Stelle weiterbearbeitet an der du in die 
unterfunktion gesprungen bist

Autor: foo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"kommst aus der Basic Ecke?
Spaghetti-Code gibts nicht mehr. Labels auch nicht."

Doch es gibt noch Spaghetti Code. Doch es gibt noch
Labels.

Ich wusste dass gleich wieder so einer kommt.
Ne technische Frage beantwortet man zuerst mit ner technischen
Antwort. Ratschläge kannst du danach anbringen und wenn
du ihn ernst meinst und dich nicht nur aufplustern willst,
dann auch in nem andern Ton.

Autor: Carolin Zapa (seobalis)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Anstatt "goto" schreibtst du einfach "return".
> Das Programm wird dann an der Stelle weiterbearbeitet an der du in die
> unterfunktion gesprungen bist

Ja! Aber dieser Fall ist nicht so gut bei mir. z.B in diesem Fall
#include<stdio.h>

int main(){
  for(..){
    if(...)
       unterprogramm1();
    if(...)
       unterprogramm2();
    label: printf("...");

  }
return 0;
}
void unterprogramm1(){
  if(..){
     if(...)
        answer();
     else
        abbruch();
     for(...)
     .....
  }  
  else ..
    abbruch();
}

void unterprogramm2(){
  if(..)
    goto label;
  else ...
}
void abbruch(){
if(..)
/*in diesem Programm soll zum label springen. Wenn ich return benutze dann wird for Schleife in Unterprogramm1 weiter laufen usw.

*/ 
}

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Deine Unterprogramme sollten einen Returncode liefern, der in Main 
ausgewertet wird:

int main(){
  int retCode;
  for(..){
    if(...)
       retCode = unterprogramm1();
    if(...)
       retCode = unterprogramm2();
    switch (retCode) {
       case 0: printf("...");
             break;
       case 1:
             break;
  }
return 0;
}

void unterprogramm2(){
  if(..)
    return 0;
  else ...

  return 1;
}

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Deine Unterprogramme sollten einen Returncode liefern,
> der in Main ausgewertet wird:

Das passt nicht ganz zu

> void unterprogramm2(){

das sollte wohl besser

> int unterprogramm2(){

lauten.

Autor: Carolin Zapa (seobalis)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rufus t. Firefly wrote:
>> Deine Unterprogramme sollten einen Returncode liefern,
>> der in Main ausgewertet wird:
>
> Das passt nicht ganz zu

Jap!

#include<stdio.h>
int main(){
  for(..){
    if(...)
       a = unterprogramm1(b);
    if(...)
       unterprogramm2();
    label: printf("...");

  }
return 0;
}
int unterprogramm1(int ...){
  if(..){
     if(...)
        answer();
     else
        abbruch();
     for(...)
     .....
  }  
  else ..
    abbruch();
  return ...;
/*
in diesem fall kann ich das nicht benutzen
*/
}

void unterprogramm2(){
  if(..)
  
  else ...
}
void abbruch(){
if(..)
/*in diesem Programm soll zum label springen. Wenn ich return benutze dann wird for Schleife in Unterprogramm1 weiter laufen usw.

*/ 
}



Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das switch-Statement in main kannst nicht einfach weglassen - na gut, es 
geht auch ein if -, das label schon.

Tipp: Versuche das Problem ohne abbruch() zu lösen - die Funktion stellt 
nur eine Sackgasse dar, die nicht zur Lösung führt.

Allein über den Wert, den unterprogramm1 zurückgibt, kannst du - mit 
Hilfe des switch - den weiteren Ablauf in main steuern.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du solltest dir wirklich überlegen, wie du dein Programm
mit strukturierten Mitteln programmieren kannst. Im Moment
bist du auf dem besten Weg zum, von foo und Gast angekündigtem
Spaghetti-Code. Inklusive aller Probleme.

>
> void abbruch(){
> if(..)
> /*in diesem Programm soll zum label springen. Wenn ich return
> benutze dann wird for Schleife in Unterprogramm1 weiter laufen usw.
> */ 
> }
>

Ja, und.
Dann lass doch einfach die Funktion abbruch() seinerseits wieder
einen Return-Code liefern, der den Aufrufer darüber aufklärt
ob jetzt abgebrochen werden soll oder nicht.
int abbruch()
{
  if( ... ) {
    // es soll tatsächlich abgebrochen werden
    ...
    return 1;
  }

  // kein Abbruch notwendig, der Aufrufer kann weiterarbeiten
  return 0;
}

und der Aufrufer hält sich natürlich daran, was ihm die Funktion
abbruch() vorschreibt
int unterprogramm1(int ...){
  if(..){
     if(...)
        answer();
     else
        if( abbruch() )
          return 0;
     for(...)
     .....
  }  
  else ..
    if( abbruch() )
      return 0;

  return 1;
}

Und natürlich basiert dann auch main() seine Entscheidung wie es
weiter geht darauf, welchen Wert unterprogramm1 zurückliefert.
Und so weiter und so weiter.

Was eine Funktion tun soll, kann mit den Argumenten einer
Funktion gesteuert werden. Den Rückgabewert einer Funktion
kann man aber wunderbar dazu benutzen, damit die Funktion dem
Aufrufer mitteilt, wie es weiter gehen soll.

Auch wenn mich foo jetzt gleich wieder schimpfen wird:
Vergiss goto, setjmp und longjmp!
Es gibt ein paar Ausnahmefälle in denen diese Dinge sinnvoll
sind. Aber als Anfänger wirst du die nächsten 2 Jahre mit
einiger Sicherheit nicht auf solche Fälle stossen. Und wenn
sie dann da sind, hast du genug Erfahrung, damit das dann nicht
in Spaghetti-Code ausartet.

Autor: Carolin Zapa (seobalis)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann ich vllt #ifndef oder #ifdef benutzen? Weil ich in der Funktion 
Abbruch einen Poiterwert zurückgeben muss :(

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Carolin Zapa wrote:
> Kann ich vllt #ifndef oder #ifdef benutzen? Weil ich in der Funktion
> Abbruch einen Poiterwert zurückgeben muss :(

Ganz ehrlich:
Bist du sicher, dass du nicht ein paar Grundlagenstunden zum
Thema 'Programmieren in C' ausgelassen hast?

#ifndef, #ifdef
haben mit dieser Problematik nichts, aber auch gar nichts zu tun.

Autor: Carolin Zapa (seobalis)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger wrote:
> Carolin Zapa wrote:
>> Kann ich vllt #ifndef oder #ifdef benutzen? Weil ich in der Funktion
>> Abbruch einen Poiterwert zurückgeben muss :(
>
> Ganz ehrlich:
> Bist du sicher, dass du nicht ein paar Grundlagenstunden zum
> Thema 'Programmieren in C' ausgelassen hast?
>

Deswegen bin ich doch Anfänger

> #ifndef, #ifdef
> haben mit dieser Problematik nichts, aber auch gar nichts zu tun.
Also wenn ich abbruch als eine programm definiert und mit z.B.
#define ABBRUCH

also dann kann ich doch in mein hauptprogramm mit
#ifndef ABBRUCH

....
#else

#endif
arbeiten

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Carolin Zapa wrote:
> Karl heinz Buchegger wrote:
>> Carolin Zapa wrote:
>>> Kann ich vllt #ifndef oder #ifdef benutzen? Weil ich in der Funktion
>>> Abbruch einen Poiterwert zurückgeben muss :(
>>
>> Ganz ehrlich:
>> Bist du sicher, dass du nicht ein paar Grundlagenstunden zum
>> Thema 'Programmieren in C' ausgelassen hast?
>>
>
> Deswegen bin ich doch Anfänger
>
>> #ifndef, #ifdef
>> haben mit dieser Problematik nichts, aber auch gar nichts zu tun.
> Also wenn ich abbruch als eine programm definiert und mit z.B.
> #define _ABBRUCH_
>
> also dann kann ich doch in mein hauptprogramm mit
> #ifndef _ABBRUCH_
>
> ....
> #else
>
> #endif
> arbeiten

Nein.
Noch mal. #ifdef und #indef haben nicht das Geringste mit
deinem Problem bzw. dessen Lösung zu tun. Diese 'Werkzeuge'
benötigt man für etwas völlig anderes.

Du kennst mitlerweile die Lösung. Die lautet: Argumente
gehen in eine Funktion hinein und werden unter anderem
dazu benutzt das Verhalten einer Funktion zu steuern.
Rückgabewerte einer Funktion werden dazu benutzt, dass
die Funktion ihrem Aufrufer mitteilen kann, wie es weiter
geht.
Der Rest sind ein paar if-else oder switch-case und du bist
dabei.

Das ist weder Raketentechnik noch besonders schwer.

> Weil ich in der Funktion
> Abbruch einen Poiterwert zurückgeben muss :(

Na dann gib doch einen Pointerwert zurück. Du kannst ja
vereinbaren, dass ein Rückgabewert von NULL als
'alles Abbrechen' gedeutet wird.
Falls das nicht geht, dann brauchst du 2 Returnwerte.
Da das aber in C nicht geht, musst du einen 'Rückgabewert'
über die Argumentschnittstelle zurückliefern. Ich würde
mal sagen, das wird wohl der Pointer werden (Generell
ist es in solchen Fällen meist besser, wenn der eigentliche
Returnwert für Fehler/Status-Rückgabe benutzt wird und der
Rest über die Argumentschnittstelle)

Am Beispiel eines char-Pointers, der von Abbruch geliefert
wird und zb irgendeinen Statustext angibt:
int Abbruch( char** ppPtr )
{
  if( .... )
  {
    ...
    *ppPtr = "Text";
    return 1;
  }

  *ppPtr = "Alles OK";
  return 0;
}

Aufruf:
  ...
  char* FehlerTxt;

  for( ....
    if( Abbruch( &FehlerTxt ) )
      // Abbruch hat gemeldet, dass abgebrochen werden soll
      // na dann machen wir das auch
      return;

    // Abbruch will nicht wirklich, dass abgebrochen wird
    // also machen wir das hier auch nicht, es geht weiter
    // in der Schleife. Aber Abbruch hat einen Text geliefert
    // den mal ausgeben.
    printf( "%s", FehlerTxt );
  }


Das, Funktionsargumente und Rückgabewerte, sind die Werkzeuge
mit denen man so ein Problem behandelt. Und damit kann man jede
wie auch immer geartete Situation deiner Problem-Machart in den
Griff kriegen. Argumente gehen nicht nur in eine Funktion hinein,
sondern eine Funktion kann auch Ergebnisse über die Argument-
schnittstelle zurückliefern.

Autor: Minetti (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das geht so nicht. Die #-Präprozessoranweisungen werden zur 
Kompiliertzeit ausgeführt, nicht zur Laufzeit des Programmes.

Übrigens... was macht der Compiler mit dem Stack, wenn man 
Unterfunktionen nicht mit return sondern mit goto verlässt? Würde mich 
wundern, wenn er so schlau ist und die Rücksprungadresse & Co wieder 
runternimmt...

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Minetti wrote:
> Das geht so nicht. Die #-Präprozessoranweisungen werden zur
> Kompiliertzeit ausgeführt, nicht zur Laufzeit des Programmes.
>
> Übrigens... was macht der Compiler mit dem Stack, wenn man
> Unterfunktionen nicht mit return sondern mit goto verlässt?

Probiers aus.
Du kommst mit goto nicht aus einer Funktion heraus.

> Würde mich
> wundern, wenn er so schlau ist und die Rücksprungadresse & Co wieder
> runternimmt...

setjmp, longjmp muessen genau das machen.

Autor: Oops (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Übrigens... was macht der Compiler mit dem Stack, wenn man
>Unterfunktionen nicht mit return sondern mit goto verlässt? Würde mich
>wundern, wenn er so schlau ist und die Rücksprungadresse & Co wieder
>runternimmt...

Das ist genau der Witz warum man nur innerhalb eines Blocks mit Goto 
springen darf. Dann ist der Stack nämlich immer intakt. Man kann also 
auch eine Funktion auch nicht mit goto verlassen, weil das auch hiesse 
den Block zu verlassen.

Für die anderen Fälle gibt es eben setjmp/longjmp. Die merken sich die 
Stacktiefe.


Gruss
Oops

Autor: Oops (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oops! Da hat sich schon wieder was überschnitte. ;-)

Gruss
Oops

Autor: Oops (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der tiefere Grund ist folgender:
goto und label sind in C definiert.
Da aber keine Maschinenabhängigkeit entstehen darf,
sind sie auf den Block beschränkt.

setjmp/longjmp sind hingegen Funktionen die der Hesteller mitliefert und 
die Implementierung bezüglich Stackaufbau usw. berücksichtigen müssen.

Gruss
Oops

Autor: Carolin Zapa (seobalis)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für euere Hilfe. ich probiere das erstmal  mit dem Weg von  Karl 
heinz Buchegger (kbuchegg)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.