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:
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.
>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.
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.
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
intfunktionXYZ(void)
2
{
3
if(yxz)
4
{
5
return0;
6
}
7
elseif(abc)
8
{
9
returniVar;
10
}
11
else
12
{
13
return12;
14
}
15
}
Nur um die Nachfrage zu beantworten; eigentlich tut es hier nichts
zur Sache ist und ist auch nicht besonders relevant...
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;
}
Ach, das ist wieder so eine Sache mit Theorie und Praxis.
Schau dir mal das an:
1
intfoo(void){
2
intres=0;
3
4
res=a();
5
if(!res){
6
res=b();
7
if(!res){
8
res=c();
9
}
10
}
11
returnres;
12
}
Und dann das:
1
intfoo(void){
2
intres=0;
3
4
res=a();
5
if(res)returnres;
6
7
res=b();
8
if(res)returnres;
9
10
res=c();
11
returnres;
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.
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:
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.
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.
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
;-))
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.
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...
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
casea:returnb;
5
casec:returnd;
6
// ... usw.
7
}
8
}
Ich schließe mich daher an, Verstehbarkeit geht vor Dogmatismus.
Peter
> 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
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
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...
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
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.
@ 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
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.
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.
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.