Hallo zusammen,
ich benötige gerade ein Konstrukt der Form: Probier das, dann das, dann
das usw. und wenn das letzte fehlschlägt, erzeuge einen Fehler.
In Quelltext sieht das momentan so aus:
1
intfoo(intprm,charc)
2
{
3
intret=tryToDoWhatIWantYouToDo(c);
4
5
if(ret==EXIT_SUCCESS)
6
{
7
continueWithTheStuffYouStarted(prm);
8
returnEXIT_SUCCESS;
9
}
10
else
11
{
12
// Zeichen nicht vorhanden -> Ersatzzeichen
13
ret=foo(prm,'@');
14
if(ret==EXIT_FAILURE)
15
{
16
ret=foo(prm,'#');
17
if(ret==EXIT_FAILURE)
18
{
19
ret=foo(prm,'A');
20
if(ret==EXIT_FAILURE)
21
{
22
ret=foo(prm,'0');
23
if(ret==EXIT_FAILURE)
24
{
25
error("Invalid character")
26
}
27
}
28
}
29
}
30
returnEXIT_FAILURE;
31
}
32
}
Wenn ich jetzt noch ein paar Sachen ausprobiere, bevor ich den Fehler
ausgebe, sieht das am Ende so aus, wie eine schriftliche Division in der
Grundschule.
Mir fallen ein paar Möglichkeiten ein, wie ich das weniger länglich
schreiben könnte. Aber vorher interessiert mich:
Gibt es ein Standard-Design-Pattern für diese Art von Problemstellung?
Viele Grüße
W.T.
Walter T. schrieb:> Gibt es ein Standard-Design-Pattern für diese Art von Problemstellung?
Siehe oben: Entweder verkette ich das im if() mit && oder mit || - je
nachdem, wie die Logik ist.
Dann wird das Ganze nicht so länglich und ist sogar noch lesbarer als
die multiplen if-Statements.
Frank M. schrieb im Beitrag #5342018:
> am Ende der Funktion vergessen hat.
Ich hatte mich exakt an sein Vorbild gehalten, das fehlende Semikolon
inklusive. Aber das Hauptproblem ist die Rekursion, und die hast du auch
übersehen. ;-)
A. K. schrieb:> Ich hatte mich exakt an sein Vorbild gehalten, das fehlende Semikolon> inklusive. Aber das Hauptproblem ist die Rekursion, und die hast du auch> übersehen. ;-)
Upps, die hatte ich tatsächlich übersehen. Und nicht nur das, auch das
return im else-Zweig fiel mir nicht auf. Damit kann die Zuweisung "ret =
foo(...)" tatsächlich entfallen.
Die Rekursion kann man eigentlich ziemlich einfach plattmachen:
1
staticintbar(intprm,charc)
2
{
3
intret=tryToDoWhatIWantYouToDo(c);
4
5
if(ret==EXIT_SUCCESS)
6
{
7
continueWithTheStuffYouStarted(prm);
8
returnEXIT_SUCCESS;
9
}
10
returnEXIT_FAILURE;
11
}
12
13
intfoo(intprm,charc)
14
{
15
if(bar(prm,c)==EXIT_FAILURE)
16
{
17
if(bar(prm,'@')==EXIT_FAILURE&&
18
bar(prm,'#')==EXIT_FAILURE&&
19
bar(prm,'A')==EXIT_FAILURE&&
20
bar(prm,'0')==EXIT_FAILURE)
21
{
22
error("Invalid character")
23
}
24
returnEXIT_FAILURE;
25
}
26
returnEXIT_SUCCESS;
27
}
Oder habe ich etwas übersehen? Ich verstehe auch nicht, warum auch bei
erfolgreich gefundenem Ersatzzeichen ein EXIT_FAILURE zurückgegeben
werden soll.
EDIT:
Ein # durch @ ersetzt.
Danke für die Antworten.
Ja - das Semikolon habe ich vergessen.
Rekursion: Stimmt. Das könnte zum Problem werden.
Die Funktion ist - wie so oft - ein gewachsenes Konstrukt. Ursprünglich
wurde maximal ein Ersatzzeichen ausprobiert, womit die Rekursionstiefe
auf 1 begrenzt war. Mit wachsender Anzahl an Ersatzzeichen ist das
eigentlich nicht mehr tragbar. Ich werde das Design also komplett
ändern, wodurch die urspruengliche Fragestellung entfällt.
Frank M. schrieb:> warum auch bei> erfolgreich gefundenem Ersatzzeichen ein EXIT_FAILURE zurückgegeben> werden soll.
Ein Ersatzzeichen ist eben nicht das, was die Funktion ursprünglich mal
bearbeiten sollte.
Walter T. schrieb:> Rekursion: Stimmt. Das könnte zum Problem werden.
Dann mach es so wie oben dargestellt mit bar() und foo(). Dann gibts
keine Rekursion mehr.
> Ein Ersatzzeichen ist eben nicht das, was die Funktion ursprünglich mal> bearbeiten sollte.
Okay :-)
Walter T. schrieb:> So sieht die Funktion jetzt nach dem "Refactoring" aus:
Leidest du unter einer Operatoren-Allergie?
In dem Fall empfehle ich COBOL statt C. ;-)
Dann wenigstens optisch so:
if( tryToDoWhatIWantYouToDo('@') == EXIT_SUCCESS )
;
else if( tryToDoWhatIWantYouToDo('#') == EXIT_SUCCESS )
;
else if( tryToDoWhatIWantYouToDo('A') == EXIT_SUCCESS )
Damit das Semikolon nicht so falsch aussieht.
A. K. schrieb:> Leidest du unter einer Operatoren-Allergie?
Nein. Wohin gehört Deiner Meinung nach einer?
A. K. schrieb:> In dem Fall empfehle ich COBOL statt C.
Gibt es nicht für meine Zielplattform. Fortran auch nicht.
Walter T. schrieb:>> Leidest du unter einer Operatoren-Allergie?>> Nein. Wohin gehört Deiner Meinung nach einer?
if( tryToDoWhatIWantYouToDo('@') != EXIT_SUCCESS
&& tryToDoWhatIWantYouToDo('#') != EXIT_SUCCESS
&& tryToDoWhatIWantYouToDo('A') != EXIT_SUCCESS
&& tryToDoWhatIWantYouToDo('0') != EXIT_SUCCESS)
error("Invalid character");
Walter T. schrieb:> Nein. Wohin gehört Deiner Meinung nach einer?
A.K. meinte das Semikolin am Ende der if-Zeilen. Das sieht so einfach
"aus Versehen" aus. Nach ein paar Monaten kommst Du dann auch nochmal
ins Grübeln, ob das jetzt falsch ist oder nicht.
Ich schreibe bei so etwas immer:
1
if(....)
2
{
3
;
4
}
um herauszustellen, dass das Semikolon Absicht ist. Deshalb meinte
auch A.K., dass Du es zumindest auf eine extra Zeile setzen solltest.
A. K. schrieb:> if( tryToDoWhatIWantYouToDo('@') != EXIT_SUCCESS> && tryToDoWhatIWantYouToDo('#') != EXIT_SUCCESS> && tryToDoWhatIWantYouToDo('A') != EXIT_SUCCESS> && tryToDoWhatIWantYouToDo('0') != EXIT_SUCCESS)> error("Invalid character");
In der Präprozessor-Sprache hätte ich es so geschrieben.
In C fällt das für mich unter die Rubrik "Geschmacksache".
A. schrieb:> Wenn es noch mehr werden:> char * zeichen = "@#A0";>> for(uint8_t i = 0; i < strlen(zeichen); i++) ...
Das sollte doch m.E. die Grundlage sein, abgesehen vom falschen
Rückgabewert.
Ich gehe zudem davon aus, dass die Ersatzzeichen nicht bis zu 4 Mal
ausprobiert werden sollten, sondern nur einmal. Dann ergäbe sich z.B.:
Achim S. schrieb:> Ausrollen UND do while?
Das ist die Lösung für Leute, die eigentlich ein "goto" zur
Fehlerbehandlung schreiben wollen, sich aber nicht trauen, dazu offen zu
stehen.
>Achim S. schrieb:>> Ausrollen UND do while?>Das ist die Lösung für Leute, die eigentlich ein "goto" zur>Fehlerbehandlung schreiben wollen, sich aber nicht trauen, dazu offen zu>stehen.
Diese do {} while(0); mit breaks - Lösung von Peter Dannegger finde ich
am besten lesbar vom all dem was hier bis jetzt zu sehen war.
Ein mal habe ich genau so ein Konstrukt nach mehreren hin und her auch
verwendet. ( do {} while(0); mit mehreren breaks. )
Dabei musste ich auch an goto denken. Trotzdem habe ich mich dafür
entschieden. Ist es wirklich zu sehen wie ein goto? oder kann man es
doch ausnahmsweise verwenden?
Gruß, Jan
Jan schrieb:> Dabei musste ich auch an goto denken. Trotzdem habe ich mich dafür> entschieden. Ist es wirklich zu sehen wie ein goto?
Ich finde es schlechter als goto.
Danke für Eure Meinungen,
> Ich finde es schlechter als goto
Ich sehe es nicht so kritisch. Oft findet man Ähnliches, wenn ein Array
durchsucht wird.Dort geht man auch mit einem break aus der Schleife
raus, nach dem man das gesuchte Element gefunden hat.
Wenn die Schleife, die man mit break unterbricht, kurz und übersichtlich
ist, finde ich es in Ordnung mit break zu unterbrechen. Alles andere
führt dazu, das es aussieht wie eine "schriftliche Division in der
Grundschule", oder es endet mit Tausenden klammern und else-Ausdrücken.
Warum hat man den break eingeführt? Nur für die switch case Anweisung?
Es verhält sich halt wie ein goto.
Ähnliches ist es mit continue.
Gruss,
Jan
Gerade in so einem Fall, wo es an mehreren Stellen zu einem Abbruch des
Verarbeitungsfluss kommen kann und dann immer das selbe getan werden
soll, dann drängt sich das goto doch quasi auf.
Leider ist das goto zu unrecht verpönt, aber das leigt eigentlich nur
daran, dass es gerade Anfänger einlädt schmu zu Treiben. Aber zum
Abbrechen von Abläufen oder mehrdimensionalen Iterationen ist es meiner
Meinung nach die lesbarste und flexibelste Lösung. Solche Konstrukte
habe ich sogar schon in Linux Kerneltreibern gesehen...
Jan
Das sogar richtete sich eher an die Verteufelung und die allgemeinen
Ratschläge, dass das goto eine Ausgeburt des Teufels ist und unter gar
keinen Umständen verwendet werden darf, Michael ;-)
Die letzten zwei Posts vom Autor Jan (Gast) sind nicht von mir.
10:22 und 10:25
(Mit mir meine ich, der Jan der sich hier zu diesem Thema das erste mal
geäußert hat)
Ich werde mir ein Account anlegen und nicht mehr anonym schreiben.
Gruss,
Jan
Michael R. schrieb:>> goto eine Ausgeburt des Teufels ist>> Ach, du meinst das mit den sieben Reitern der Apokalypse und so ;-)
Das geht hierauf zurück, von 1968, und bezog sich wesentlich auf einen
Programmierstil wie in unstrukturiertem Fortran:
"Edgar Dijkstra: Go To Statement Considered Harmful"
http://www.cs.utexas.edu/users/EWD/ewd02xx/EWD215.PDF
Jan schrieb:> Gerade in so einem Fall, wo es an mehreren Stellen zu einem Abbruch des> Verarbeitungsfluss kommen kann und dann immer das selbe getan werden> soll, dann drängt sich das goto doch quasi auf.
Ja, aber in der Aufgabe hier ist der Sprung unnötig, da reicht return (
siehe oben Beitrag "Re: C: try this, then this, then this, then this, then this.")
Wäre ein goto sinnvoll, wäre es mir egal, ob goto oder do while.
Peter D. schrieb:> do{> if( a ) break;> if( b ) break;> if( c ) break;> if( d ) break;> do_something();> }while(0);A. K. schrieb:> if( tryToDoWhatIWantYouToDo('@') != EXIT_SUCCESS> && tryToDoWhatIWantYouToDo('#') != EXIT_SUCCESS> && tryToDoWhatIWantYouToDo('A') != EXIT_SUCCESS> && tryToDoWhatIWantYouToDo('0') != EXIT_SUCCESS)> error("Invalid character");
Haben diese beiden Entwurfsmuster auch (jeweils) einen Namen?
Jan schrieb:> Danke für Eure Meinungen,>> > Ich finde es schlechter als goto>> Ich sehe es nicht so kritisch. Oft findet man Ähnliches, wenn ein Array> durchsucht wird.Dort geht man auch mit einem break aus der Schleife> raus, nach dem man das gesuchte Element gefunden hat.
Ja, aber da ist es dann auch eine richtige Schleife und nicht nur ein
Pseudo-Schleifenkonstrukt, der nur dazu dient, break verwenden zu
können.
Mich stört nicht die Verwendung von break, sondern die von while für
etwas, das gar keine Schleife ist.
Rolf M. schrieb:> Mich stört nicht die Verwendung von break, sondern die von while für> etwas, das gar keine Schleife ist.Das Problem lässt sich leicht lösen:
Falls es auch C++ sein darf (ok, im Subject steht C, trotzdem gehe ich
mal davon aus, dass man das betreffende Modul auch mit einem
C++-Compiler übersetzen kann):
Michael R. schrieb:> Jan schrieb:> Solche Konstrukte> habe ich sogar schon in Linux Kerneltreibern gesehen...>> warum "sogar" ?
Weil dort keine Anfänger coden sondern Leute auf Guru-Level, solche die
Treiberberquelltext beim Frühstück lesen statt der Zeitung.
Rolf Magnus schrieb :
>Ja, aber da ist es dann auch eine richtige Schleife und nicht nur ein>Pseudo-Schleifenkonstrukt, der nur dazu dient, break verwenden zu>können.>Mich stört nicht die Verwendung von break, sondern die von while für>etwas, das gar keine Schleife ist.
Dem muss ich zustimmen. Eine do while(0); ist keine schleife. Eigentlich
missbraucht man an dieser Stelle die Sprache, es ist Irreführend für den
Leser. Man könnte vielleicht sogar eine Compilerwarnung an dieser Stelle
erwarten.
Mit goto wäre es sauberer an dieser Stelle. Da goto aber so verpönt ist,
benutzt es kaum jemand.
Dafür neigt man lieber zum Missbrauch von Schleifen.
Gruss,
Jan
Karl schrieb:> Muhaha!>> http://cdn3.spiegel.de/images/image-662536-galleryV9-erjl-662536.jpg
Nett :-)
Aus diesem Grunde benutze ich grundsätzlich unterhalb jeder
Kontrollstruktur wie if, while, for usw. geschweifte Klammern. Die
beiden gotos innerhalb dieser Klammern hätten dann zu einer
Compiler-Warnung geführt und nicht zu einem Laufzeitfehler.
Frank M. schrieb:> Die beiden gotos innerhalb dieser Klammern hätten dann zu einer> Compiler-Warnung geführt
Das if hinter dem zweiten goto sollte eigentlich eine solche
"unreachable code" Warnung auslösen.
Jan schrieb:> Leider ist das goto zu unrecht verpönt, aber das leigt eigentlich nur> daran, dass es gerade Anfänger einlädt schmu zu Treiben. Aber zum> Abbrechen von Abläufen oder mehrdimensionalen Iterationen ist es meiner> Meinung nach die lesbarste und flexibelste Lösung. Solche Konstrukte> habe ich sogar schon in Linux Kerneltreibern gesehen...>
....
> {> if( foo(prm, '@') == EXIT_FAILURE ) goto failure_exit;> if( foo(prm, '#') == EXIT_FAILURE ) goto failure_exit;> if( foo(prm, 'A') == EXIT_FAILURE ) goto failure_exit;> if( foo(prm, '0') == EXIT_FAILURE ) goto failure_exit;>> //It worked, so return success> return EXIT_SUCCESS;>> //Something failed, lets report it> failure_exit:> error("Invalid character");> return EXIT_FAILURE;> }
Wenn Anfänger solchen Unsinn lesen und sowas verinnerlichen, weil sie
zwischen guten Ratschlägen und Tipps zum Murx noch nichts unterscheiden
können ...
finde ich ziemlich schlimm!
4 x mit goto zum gleichen return springen ..und vorher immer die gleiche
Funktion error(blah_blah) aufrufen - um damit die Sinnhaftigkeit von
goto in C zu demonstrieren ..... ohne Worte!!!
A. K. schrieb:> "The -Wunreachable-code has been removed, because it was unstable:"
Weia. Und das schon seit 2011! Mit so etwas hätte ich jetzt nicht
gerechnet.
A. K. schrieb:> Das if hinter dem zweiten goto sollte eigentlich eine solche> "unreachable code" Warnung auslösen.
Wer weiss wie viele Warnungen da noch drin sind. Die ignoriert man halt,
hauptsache es kompiliert.
Ich hab auch 2 unreachable code-Warnungen in meinem aktuellen Projekt.
Ich inkrementiere einen uint8 und wenn der Buffermax erreicht
(Bufferlänge) setze ich ihn zurück. Nun ist Buffermax = 256, wird also
nie erreicht bzw. automatisch wieder Null. Trotzdem lasse ich die
Abfrage drin, weil ich ja mal die Bufferlänge verringern könnte und dann
ist die wichtig. Bekomme also immer Compilerwarnungen, hab aber auch
keine andere Lösung dafür. (Nein, uint16 verwenden ist keine Lösung ;-))
Wilhelm M. schrieb:> Falls es auch C++ sein darf (ok, im Subject steht C, trotzdem gehe ich> mal davon aus, dass man das betreffende Modul auch mit einem> C++-Compiler übersetzen kann):>>
Bernd K. schrieb:> Michael R. schrieb:>> Jan schrieb:>> Solche Konstrukte>> habe ich sogar schon in Linux Kerneltreibern gesehen...>>>> warum "sogar" ?>> Weil dort keine Anfänger coden sondern Leute auf Guru-Level, solche die> Treiberberquelltext beim Frühstück lesen statt der Zeitung.Karl schrieb:> Muhaha!>> http://cdn3.spiegel.de/images/image-662536-galleryV9-erjl-662536.jpg
Dieser Link hat aber weder mit Linux noch mit Kerneltreibern etwas zu
tun, sondern zeigt allenfalls, dass bei Apple die Codequalität seit
Steve Wozniaks Rückzug etwas nachgelassen hat ;-)
Walter K. schrieb:> x mit goto zum gleichen return springenWalter K. schrieb:> 4 x mit goto zum gleichen return springen
Er springt nicht zum return. Sonst hätt er gleich return hinschreiben
können.
Bernd K. schrieb:> Walter K. schrieb:>> 4 x mit goto zum gleichen return springen>> Er springt nicht zum return. Sonst hätt er gleich return hinschreiben> können.
Lesekompetenz?
wenn Du meinen Satz komplett gelesen hättest....
Walter K. schrieb:>> Er springt nicht zum return. Sonst hätt er gleich return hinschreiben>> können.>> Lesekompetenz?>> wenn Du meinen Satz komplett gelesen hättest....
Schreibkompetenz?
Du hast geschrieben daß er vorher eine Funktion error() ausführt und
danach mit goto zum return springt. Das ist nicht der Fall, er springt
nicht mit goto zum return und error() wird auch nicht vor dem goto
aufgerufen. Dein Geschreibsel war völlig losgelöst von der Realität,
insgesamt inkoheränt und am Ende hast Du dann auch noch vergessen zu
schreiben was Du eigentlich sagen wolltest, es endet einfach abrupt ohne
zur Kernaussage gelangt zu sein. Wenn Du irgendetwas sagen wolltest dann
lerne bitte Dich vernünftig zu artikulieren.
Bernd K. schrieb:> Du hast geschrieben daß er vorher eine Funktion error() ausführt und> danach mit goto zum return springt. Das ist nicht der Fall, er springt> nicht mit goto zum return und error() wird auch nicht vor dem goto> aufgerufen. Dein Geschreibsel war völlig losgelöst von der Realität,> insgesamt inkoheränt und am Ende hast Du dann auch noch vergessen zu> schreiben was Du eigentlich sagen wolltest, es endet einfach abrupt ohne> zur Kernaussage gelangt zu sein. Wenn Du irgendetwas sagen wolltest dann> lerne bitte Dich vernünftig zu artikulieren.
Mein Gott ... anstatt Dich hier aufzublasen, von Kohärenzen zu
schwadronieren und viel Zeit zu vergeuden ... lies endlich mal meinen
Beitrag!
"...4 x mit goto zum gleichen return springen ..UND VORHER immer die
gleiche
Funktion error(blah_blah) aufrufen ..."
Walter K. schrieb:> "...4 x mit goto zum gleichen return springen ..UND VORHER immer die> gleiche> Funktion error(blah_blah) aufrufen ..."
Ja, und das ist falsch, denn er ruft nicht die funktion error(blah blah)
auf und springt DANACH per goto zum return.
Ich weiß nicht was für Dich das größere Problem ist, den Code überhaupt
erstmal zu lesen über den Du Dich so grundlos aufbläst oder in Worte zu
fassen was Du eigentlich mitteilen willst. Und wir wissen immer noch
nicht was Du eigentlich sagen willst oder was an dem Code den Du nicht
verstanden hast Deiner Meinung nach falsch sein soll.
Walter K. schrieb:> 4 x mit goto zum gleichen return springen ..und vorher immer die gleiche> Funktion error(blah_blah) aufrufen - um damit die Sinnhaftigkeit von> goto in C zu demonstrieren ..... ohne Worte!!!
Mir erschließt sich nicht, wo du da ein Problem siehst. Muss man deiner
Meinung nach mit jedem goto zu einem anderen return springen? Und darf
man vor diesen returns keine Funktion aufrufen? Oder irgendwie wieder
verzweigen, damit es immer eine andere Funktion ist? Deshalb ist das
goto ja da, weil es immer die selbe Kombination aus dem Funktionsaufruf
und dem return ist. Was ist dein Alternativ-Vorschlag? Viermal den
gleichen Funktionsaufruf mit jeweils darauf folgendem return
hinschreiben?
Walter K. schrieb:> Mein Gott ... anstatt Dich hier aufzublasen, von Kohärenzen zu> schwadronieren und viel Zeit zu vergeuden ... lies endlich mal meinen> Beitrag!
Das haben wir hier alle.
> "...4 x mit goto zum gleichen return springen ..UND VORHER immer die> gleiche Funktion error(blah_blah) aufrufen ..."
Ja, die Funktion wird aber nicht VOR dem goto aufgerufen, und es wird
nicht zum return gesprungen. Ich vermute, du hast dich nur ungeschickt
ausgedrückt. Und dein "..." besteht dann nur noch aus "ohne Worte" mit
drei Ausrufezeichen. Das ist keine Erklärung.
Karl schrieb:> Ich hab auch 2 unreachable code-Warnungen in meinem aktuellen Projekt.> Ich inkrementiere einen uint8 und wenn der Buffermax erreicht> (Bufferlänge) setze ich ihn zurück. Nun ist Buffermax = 256, wird also> nie erreicht bzw. automatisch wieder Null. Trotzdem lasse ich die> Abfrage drin, weil ich ja mal die Bufferlänge verringern könnte und dann> ist die wichtig. Bekomme also immer Compilerwarnungen, hab aber auch> keine andere Lösung dafür. (Nein, uint16 verwenden ist keine Lösung ;-))
Mit einem #if prüfen, ob deine maximale Bufferlänge UINT8_MAX
entspricht, wäre zu einfach? Bei der Gelegenheit könntest du auch gleich
noch ein zweites #if einbauen, das zu einem Fehler führt, wenn du
versehentlich mal einen Wert einträgst, der größer ist.
>> In der Kürze liegt die Würze.
Ist das schon Perl oder kann das weg?
---
Mir gefallen die Ansätze mit "@#A0" und Schlaufe besser: diese bringen
das Konzept Programmieren her und ist Zukunftgerichtet. Sollten andere
Prüffälle nötig sein bleibt die Programmlogik unangetastet, das kann
sogar in eine parametrierte Funktion ausfaktoriert werden;
bewährter/getesteter Code (durchaus auch in Binärform) in einer lib
zur Wiederverwendung vorgehalten werden.
Alles andere ist... Sackgasse ?
>>>> In der Kürze liegt die Würze.>> Ist das schon Perl oder kann das weg?
Wenns Perl wäre, könnte es in der Tat weg ...
Die Zeichen wie '@' oder '$' stammen vom TO.
>> Mir gefallen die Ansätze mit "@#A0" und Schlaufe besser: diese bringen> das Konzept Programmieren her und ist Zukunftgerichtet.
Was meinst Du denn da mit? Und was ist Schlaufe ?
> Sollten andere> Prüffälle nötig sein bleibt die Programmlogik unangetastet, das kann> sogar in eine parametrierte Funktion ausfaktoriert werden;
Was ist denn bei Dir ein parametrierte Funktion? Meinst Du parametrische
Polymorphie?
Wilhelm M. schrieb:>> Mir gefallen die Ansätze mit "@#A0" und Schlaufe besser: diese bringen>> das Konzept Programmieren her und ist Zukunftgerichtet.>> Was meinst Du denn da mit? Und was ist Schlaufe ?
Das ist Schweizerdeutsch und heißt auf Deutschdeutsch "Schleife" ;-)
Der "Programmiersprachentheaterintendant" bezieht sich vermutlich auf
den folgenden Vorschlag, wo die zu prüfenden Zeichen in einer expliziten
Schleife abgearbeitet werden:
A. schrieb:> char * zeichen = "@#A0";>> for(uint8_t i = 0; i < strlen(zeichen); i++){> if(foo(prm, zeichen[i]) != EXIT_FAILURE){> return EXIT_SUCCESS;> }> }>> return EXIT_FAILURE;
Für mich persönlich ist es prinzipiell guter Stil, explizite Schleifen
durch implizite zu ersetzen, wie du es in deinem Beispiel getan hast.
Folds sind generell eine gute Möglichkeit zur Notation akkumulierender
Berechnungen/Auswertungen, und werden deswegen von den meisten neueren
Programmiersprachen unterstützt, im Fall von C++17 sogar durch eine
spezielle Syntax.
Was mir bei den C++17-Folds aber nicht so sehr gefällt ist die Tatsache,
dass sie die zu faltende Sequenz in Form eines Parameter-Packs erwarten,
weswegen du in deinem Beispiel den Fold in einen Lambda-Ausdruck packen
musstest, der einzig und allein dazu dient, die Sequenz der zu prüfenden
Zeichen in das passende Format zu konvertieren.
In funktionalen Sprachen, aus denen die Folds übernommen wurden, sieht
das i.Allg. sehr viel eleganter aus. So würde man bspw. den C++-Ausdruck
1
[](auto...cc){(f(cc)&&...);}('@','#','A','0')
in Haskell einfach als
1
all f "@#A0"
schreiben. Die Bibliotheksfunktion all prüft, ob die Funktion f für
jedes Element des zweiten Arguments True ergibt.
Aber wir schweifen ab. Der TE programmiert in C, und da gibt es Folds
weder im Sprachumfang noch in der Standardbibliothek. Unter dieser
Einschränkung ist obige Schleifenlösung IMHO schon in Ordnung.
Yalu X. schrieb:> In funktionalen Sprachen, aus denen die Folds übernommen wurden, sieht> das i.Allg. sehr viel eleganter aus. So würde man bspw. den C++-Ausdruck>> [](auto... cc) { (f(cc) && ...); } ('@', '#', 'A', '0')>> in Haskell einfach als>> all f "@#A0">> schreiben. Die Bibliotheksfunktion all prüft, ob die Funktion f für> jedes Element des zweiten Arguments True ergibt.
Es gibt seit C++11 all_of
(http://en.cppreference.com/w/cpp/algorithm/all_any_none_of). Nicht ganz
das gleiche, da es auf Iteratoren basiert, aber "bald" gibt es all_of
auch für ranges dank ranges-TS
(http://en.cppreference.com/w/cpp/experimental/ranges/algorithm/all_any_none_of).
mh schrieb:> Es gibt seit C++11 all_of> (http://en.cppreference.com/w/cpp/algorithm/all_any_none_of). Nicht ganz> das gleiche, da es auf Iteratoren basiert,
Ja, diese Funktionen mit Iteratoren als Argumente sind aber gruselig,
wenn man in 99% der Fälle den gesamten Container bearbeiten möchte und
statt des Variablennamens immer dieses lästige begin()-/end()-Gedöns
hinschreiben muss. Die Idee ist gut, die Umsetzung schlecht.
> aber "bald" gibt es all_of auch für ranges dank ranges-TS>
(http://en.cppreference.com/w/cpp/experimental/ranges/algorithm/all_any_none_of).
Danke für die Info. Darauf warte ich schon mindestens 20 Jahre.
Ich mochte C++ ja noch nie so besonders und nutze es – dort, wo ich es
nutze – eher aus Mangel vernünftiger Alternativen denn aus Überzeugung.
Wenn ich aber die Fortschritte seit C++11 und die angekündigten
zukünftigen Erweiterungen verfolge, sehe ich mich auf dem besten Weg,
irgendwann doch noch C++-Fan zu werden :)
Ich frage mich nur, warum es fast 3 Jahrzehnte dauern musste, bis dieser
plötzliche Schub zum Positiven hin eingesetzt hat.
Yalu X. schrieb:> mh schrieb:>> Es gibt seit C++11 all_of>> (http://en.cppreference.com/w/cpp/algorithm/all_any_none_of). Nicht ganz>> das gleiche, da es auf Iteratoren basiert,>> Ja, diese Funktionen mit Iteratoren als Argumente sind aber gruselig,> wenn man in 99% der Fälle den gesamten Container bearbeiten möchte und> statt des Variablennamens immer dieses lästige begin()-/end()-Gedöns> hinschreiben muss.
Normalerweise schreibt man sich dafür einen Adapter, in diesem Fall ein
3-zeiliges Funktionstemplate ...
> Die Idee ist gut, die Umsetzung schlecht.
Naja, die Idee von Stepanov, die Iteratoren als das Bindeglied zwischen
den Containern und den Algorithmen einzusetzen, war schon genial.
Natürlich kann man es jetzt mit concepts (ranges) besser machen ...
>> aber "bald" gibt es all_of auch für ranges dank ranges-TS
Schau bei Eric nach, der Entwurf ist dort schon recht lange zu finden.
> Danke für die Info. Darauf warte ich schon mindestens 20 Jahre.
Da hättest Du aber auch schon std::find_if_not (evtl. mit dem o.g.
Adapter) verwenden können.
> Ich mochte C++ ja noch nie so besonders und nutze es – dort, wo ich es> nutze – eher aus Mangel vernünftiger Alternativen denn aus Überzeugung.> Wenn ich aber die Fortschritte seit C++11 und die angekündigten> zukünftigen Erweiterungen verfolge, sehe ich mich auf dem besten Weg,> irgendwann doch noch C++-Fan zu werden :)
Und für mich ist es fast unbegreiflich, wie man so hartnäckig an purem C
festhalten kann: ich bin davon überzeugt, dass man 98% der Module einer
µC-SW direkt mit einem C++-Compiler übersetzen kann, und dabei kann man
sich ganz behutsam die Rosinen aus der Sprache heraus picken (aber ich
wiederhole mich ...)