Funktion mit mehreren Ausgängen

Gast #1562912
Lesenswert?

Hallo

Heute würde mir gesagt das man es tunlichst vermeiden sollte Funktionen 
mit mehreren Ausgängen zu Programmieren und die dies tut sind schlechte 
Programmier!
was sagt ihr zu diesen Thema?

Zum Beispiel:
1
int funktionXYZ(void)
2
{
3
   if(yxz)
4
     return 0;
5
   ...
6
   ...
7
   if(abc)
8
     return iVar;
9

10
   return 12;
11
}
Gast #1562924
Lesenswert?

Tom schrieb:

> Heute würde mir gesagt das man es tunlichst vermeiden sollte Funktionen
> mit mehreren Ausgängen zu Programmieren und die dies tut sind schlechte
> Programmier!

Bloedsinn. Solche Pauschalaussagen kommen immer von schlechten 
Programmierern. Richtig ist immer das, was leichter zu ueberblicken und 
zu verstehen ist - das kann mal diese, mal jene Variante sein.
Gast #1562955
Lesenswert?

Die Funktion sollte ja nur verdeutlichen was ich meine.

Er hat underanderen noch eine schöne Begründung gesagt.
- Es geht auch nicht im Struktogramm!

Hab mit Ihn auch erst ma diskutiert aber hat leider nix gebracht.
#1562981
Lesenswert?

Nils S. schrieb:
>>Wobei der obige Quelltext auch kein Schmuckstück ist.
> Und das machst du woran fest?
> Ein switch/case würde hier nichts bringen, sind zwei verschiedene
> Variablen die abgefragt werden.

Nein, von switch habe ich hier nicht geträumt.
Was mich etwas daran stört, ist der Umstand, daß von den
drei returns genau eines ausgeführt wird; das drückt sich aber
nicht offensichtlich in der Struktur aus.
Wenn man mehrere formal unabhängige if hat, von denen aber
maximal eines erfüllt sein kann, dann erfordert das beim
Erfassen einen zusätzlichen Denkschritt.
Mit if - else if - else wird es dagegen klar ausgedrückt.

Deshalb fände ich etwas in dieser Art logischer:
1
int funktionXYZ(void)
2
{
3
   if(yxz)
4
   {
5
      return 0;
6
   }
7
   else if(abc)
8
   {
9
      return iVar;
10
   }
11
   else
12
   {
13
      return 12;
14
   }
15
}

Nur um die Nachfrage zu beantworten; eigentlich tut es hier nichts
zur Sache ist und ist auch nicht besonders relevant...
Gast #1563025
Lesenswert?

das is total banane, der erste return, der ausgeführt wird, beendet die 
Funktion, scheiß egal wieviele andere noch kommen.
Mein Proggenprof steht auch drauf sowas zu schreiben:

int abs(int x) //Absoluter Betrag
{
  if(x<0)
     return x;
  return -x;
}
#1563031
Lesenswert?

Ach, das ist wieder so eine Sache mit Theorie und Praxis.
Schau dir mal das an:
1
int foo(void) {
2
  int res = 0;
3
  
4
  res = a();
5
  if (!res) {
6
    res = b();
7
    if (!res) {
8
      res = c();
9
    }
10
  }
11
  return res;
12
}
Und dann das:
1
int foo(void) {
2
  int res = 0;
3

4
  res = a();
5
  if (res) return res;
6

7
  res = b();
8
  if (res) return res;
9

10
  res = c();
11
  return res;
Was ist nun wohl übersichtlicher? Auch bei mehrfach geschachtelten 
Schleifen oder switch()-Statements ist es ganz praktisch, wenn man im 
Fehlerfall direkt den Notausgang nehmen kann und sich nicht erst mit 
Flags und breaks durch alle Blöcke hangeln muss.
Bei Code, der z.B. Aufräumarbeiten erfordert ist es aber durchaus 
sinnvoll, nur ein Funktionsende zu haben.
Gast #1563050
Lesenswert?

Tom schrieb:
> Er hat underanderen noch eine schöne Begründung gesagt.
> - Es geht auch nicht im Struktogramm!

Doch, das geht (natürlich(sic!)), zumindest in anständigen welchen, z.B. 
in Nassi-Shneiderman aka DIN 66261 :-) Man muss dazu nur wissen, dass 
(z.B.)
1
if b then
2
   block1
3
   return1
4
fi
5
block2
6
return2
semanitsch äquivalent ist mit
1
if b then
2
   block 1
3
   return1
4
else
5
   block2
6
   return2
7
fi
und das wiederum ist semantisch äquavalent mit
1
declare new __return_var
2
if b then
3
   block1
4
   __return_var := val1
5
else
6
   block2
7
   __return_var := val2
8
fi
9
return __return_var
Man muss also nur die impliziten 'else'-Zweige ins Diagramm aufnehmen. 
Bei switch/case läufts analog. ..und damit iss da Kaas bissn. (Und nein 
ich werde hier jetzt nicht den Smallstep-Beweis für die semantische 
Äquivalenz runterbeten, Beweis durch Offensichtlichkeit muss langen..).

Und zum Thema wann man was nimmt: Das hängt entscheidend von der 
Lesbarkeit ab. Extrem dienlich an dieser Stelle kann Code der folgenden 
Form sein - da wären tiefverschachtelte ifs zwar semantisch völlig 
äquivalent, aber fürs Verständnis halt extrem kontraproduktiv:
1
if b1
2
   trace (error b1)
3
   return ERROR_b1
4
if b2
5
   trace (error b2)
6
   return ERROR_b2
7
..
8
if bn
9
   trace (error bn)
10
   return ERROR_bn
11

12
return some_value
Zum Vergleich:
1
declare new __return_var
2
if b1
3
   trace (error b1)
4
   __return_var := ERROR_b1
5
else if b2
6
      trace (error b2)
7
      __return_var := ERROR_b2
8
..
9
                                    if bn
10
                                       trace (error bn)
11
                                       __return_var := ERROR_bn
12
                                    fi
13
                                 fi
14
                              fi
15
                           fi
16
..
17
   fi
18
fi
19

20
return __return_var

HTH
#1563079
Lesenswert?

Tom schrieb:
> Ja aber du hast auch 3 return leut der Aussage von meinen Lehrer darf
> man in einer Funktion max 1 return haben.

So weltfremden Unfug können nur Pauker abschwallen. Und daß es nichts 
nutzt, mit so einen Scholastiker zu diskutieren, ist selbstredend...

Wie andere schon geschrieben haben: Es kommt auf Übersichtlichkeit und 
leichte Durchschaubarkeit am.

Und den, der in der Praxis Struktogramme benutzt, den möchte ich 
sehen.
Gast #1563101
Lesenswert?

Also wie schon einige hier geschrieben haben, sollte man das IMO eher 
pragmatisch sehen. Wenn man return vernünftig anwendet, leidet die 
Übersichtlichkeit nicht. Dagegen kann es schnell verkrampft wirken, wenn 
man unbedingt die Regel, nur einen Ausgang zu nehmen, einhalten will. 
Ich wollte die Regel auch mal befolgen, habe aber schnell festgestellt, 
dass vernünftig eingesetzte return-Anweisungen viel übersichtlicher 
sind. Warum die Regel "nur ein Ausgang" bessere Programme ergeben soll, 
sehe ich ehrlich gesagt nicht, zumindest nicht in der Praxis.
#1563107
Lesenswert?

Das ist wie mit "niemals goto": es ist etwas Wahres dran in den
meisten Fällen, aber mit Verstand verwendet ist es manchmal doch
besser.

Wie mit vielen Ideologien halt.

Ich oute mich bei dieser Gelegenheit: Vor drei oder vier Jahren
habe ich auch goto benutzt, und halte es nach wie vor für richtig...
#1563126
Lesenswert?

Ich finde das mehrfache Return schon äußerst nützlich, weil ja leider 
die C-Erfinder das Break einer Schleife auch unbedingt für das Switch 
mißbrauchen mußten.
Daher gehen mehrere Abbruchbedingungen einer Schleife übersichtlich 
geschrieben nur mit Returns:
1
  for( u; v; w){
2
     //... code
3
     switch( x ){
4
       case a: return b;
5
       case c: return d;
6
       // ... usw.
7
     }
8
  }

Ich schließe mich daher an, Verstehbarkeit geht vor Dogmatismus.

Peter
#1563165
Lesenswert?

Klaus Wachtler schrieb:
> Das ist wie mit "niemals goto": es ist etwas Wahres dran in den
> meisten Fällen, aber mit Verstand verwendet ist es manchmal doch
> besser.

Hast du schon mal versucht, aus einer inneren Schleife eine umschießende 
Schleife zu verlassen?

Ohne goto kommt ein entsetzlicher Krampf dabei raus.

Es gibt in C wenige, aber durchaus gute Gründe, goto zu benutzen
#1563174
Lesenswert?

Nils schrieb:
> Neben Lesbarkeit gibt es noch einen Grund das return gezielt
> einzusetzen: Optimierung der Laufzeit.

Das glaube ich nun weniger. Heutige Optimizer sind clever genug, auch 
anders optimalen Code zu erzeugen - der hat nämlich keine Jump-Phobie 
und das Geschwätz von Paukern ist ihm sowieso wurscht...
#1563182
Lesenswert?

Der Compiler macht immer sein eigenes Ding, egal wieviel Returns und an 
welcher Stelle.

Auch wenn Du nur ein Return im Code hast, aber mehrere 
Abbruchbedingungen, dann kann er mehrere Returns draus machen.

Und wenn Du mehrere Returns hast, aber lokale Variablen aufm Stack, dann 
springt er von allen an das einzige Return am Ende, wo der Stack 
aufgeräumt wird.


Peter
Gast #1563186
Lesenswert?

Ich weis nicht, ob man solche Pauker mit Normen
beeindrucken kann, aber in der ISO/IEC 9899:TC3
steht:
1
6.8.6.4 The return statement
2
Constraints
3
1 A return statement with an expression shall not appear in a function whose return type
4
is void. A return statement without an expression shall only appear in a function
5
whose return type is void.
6
Semantics
7
2 A return statement terminates execution of the current function and returns control to
8
its caller. A function may have any number of return statements.
9
3 If a return statement with an expression is executed, the value of the expression is
10
returned to the caller as the value of the function call expression. If the expression has a
11
type different from the return type of the function in which it appears, the value is
12
converted as if by assignment to an object having the return type of the function.139

Punkt 2 sollte reichen (wenn er Englisch kann).

Sonst mit dem ganzen Wälzer (552 Seiten, 3700 KB)
http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf
erschlagen ;)

avr
Gast #1563230
Lesenswert?

@ Uhu, Peter

> Heutige Optimizer sind clever genug, ...
> Der Compiler macht immer sein eigenes Ding, egal wieviel Returns und an welcher 
Stelle...

Ok. Würdet Ihr soweit gehen zu sagen, dass solche Codeoptimierungen 'von 
Hand' bei heutigen C-Compilern nichts bringen?

Nils
Gast #1563237
Lesenswert?

Nils schrieb:

> Ok. Würdet Ihr soweit gehen zu sagen, dass solche Codeoptimierungen 'von
> Hand' bei heutigen C-Compilern nichts bringen?

Das musst du fallweise testen. Und mit der naechsten Compilerversion 
kann es wieder anders sein. Man sollte sich also vor Optimierungen gut 
ueberlegen, ob man sie wirklich braucht. Bei groesseren Projekten steckt 
meist sowieso mehr Optimierungspotential in den Algorithmen und der 
Architektur als in einzelnen Codebloecken.
Gast #1563275
Lesenswert?

Peter schrieb:

> Bei groesseren Projekten steckt
> meist sowieso mehr Optimierungspotential in den Algorithmen und der
> Architektur als in einzelnen Codebloecken.

Ja, das stimmt. Guter Hinweis - wahrscheinlich sollte man sich 
tatsächlich das Gesamtdesign ins Gedächnis rufen, anstatt in solchen 
Blöcken zu optimieren.
#1563282
Lesenswert?

Nils schrieb:
> Ok. Würdet Ihr soweit gehen zu sagen, dass solche Codeoptimierungen 'von
> Hand' bei heutigen C-Compilern nichts bringen?

Ja, so ist es. Die Compiler können das meist so gut, daß man selbst als 
Assemblerprogrammierer seine liebe Not hat, mitzuhalten. (Vom 
Zeitaufwand gar nicht zu reden.)

Allerdings ist das meistens nur eine lokale Optimierung innerhalb einer 
Funktion. Der entgehen natürlich Design-Dummheiten und genau da kann man 
als Programmierer durch gut durchdachte Struktur und vor allem 
effiziente Algorithmen sehr viel herausholen.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren