Forum: Mikrocontroller und Digitale Elektronik Funktion mit mehreren Ausgängen


von Tom (Gast)


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
}

von P. S. (Gast)


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.

von Klaus W. (mfgkw)


Lesenswert?

ja

Wobei der obige Quelltext auch kein Schmuckstück ist.

von Nils S. (kruemeltee) Benutzerseite


Lesenswert?

>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.

von Tom (Gast)


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.

von Klaus W. (mfgkw)


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...

von Tom (Gast)


Lesenswert?

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

von Flo (Gast)


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;
}

von Flo (Gast)


Lesenswert?

Vorzeichenfehler, habs grad nach dem Abschicken gemerkt ;-)

von Philipp B. (philipp_burch)


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.

von xy (Gast)


Lesenswert?

In den MISRA Richtlinien wird gefordert das die Funktionen nur einen 
Ausgang haben dürfen. Bei Sicherheitsrelevanter Software ist das so.

von g457 (Gast)


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

von Klaus W. (mfgkw)


Lesenswert?

Und was ist an MISRA so toll, außer daß einige Leute MISRA toll finden?

Wenn man sich mit einem scharfen Messer in den Finger schneiden kann,
essen wir die Kuh lieber in einem Stück.

von Uhu U. (uhu)


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.

von Klaus W. (mfgkw)


Lesenswert?

ich, aber nur gelegentlich zugegebenermaßen

Ob du mich sehen willst steht auf einem anderen Blatt :-)

von g457 (Gast)


Lesenswert?

Klaus Wachtler schrieb:
> Und was ist an MISRA so toll, außer daß einige Leute MISRA toll finden?

Na es kostet was, alles was was kostet, das ★muss★ einfach toll sein 
;-))

von Gast88 (Gast)


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.

von Klaus W. (mfgkw)


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...

von Peter D. (peda)


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

von Nils (Gast)


Lesenswert?

> Ich schließe mich daher an, Verstehbarkeit geht vor Dogmatismus.
Neben Lesbarkeit gibt es noch einen Grund das return gezielt 
einzusetzen: Optimierung der Laufzeit.

Gruß,
Nils

von Uhu U. (uhu)


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

von Uhu U. (uhu)


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...

von Peter D. (peda)


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

von avr (Gast)


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

von Klaus W. (mfgkw)


Lesenswert?

naja, ich bin kein Fan von 1000 versteckten return irgendwo.

Aber was ein C-Compiler im Extremfall können muß, und was als
elegantes Programmieren bezeichnet wird, ist nicht ganz deckungsgleich.

von Uhu U. (uhu)


Lesenswert?

Da hast du recht. Es ist wie mit einem Küchenmesser: man kann ein tolles 
Menü damit zubereiten, oder die Schwiegermutter abstechen...

von Klaus W. (mfgkw)


Lesenswert?

Eingesehen!
Das Menü wäre nur ein kurzfristiges Vergnügen.

von Nils (Gast)


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

von P. S. (Gast)


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.

von Nils (Gast)


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.

von Uhu U. (uhu)


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.

von Nils (Gast)


Lesenswert?

@ Uhu Uhuhu, Peter S., Peter D.:
Danke für Euren Einwand auf meine Antwort und Eure Erklärungen - wieder 
was gelernt, danke!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.