C Programmierbeleg in C - mit einigen Problemen

Ok, das mit dem Debug-Problem hab ich net gewusst, gut dass ihr das gesagt habt...

Man könnte ja rein theoretisch auch die Eingabe in eine andere Variable einlesen, die Länge überprüfen und falls es i.O. ist in das Array schreiben. Wäre nur etwas umständlich...

Ob man mit fgets o.ä. auch die maximal eingelesene Anzahl an Char's eingeben/prüfen kann weiß ich grad nich aus dem Kopf, deswegen stell ich das mal so in den Raum, müsst ich erst im Skript blättern. Aber danke für die Tipps, sonst hätt ich wohl wirklich Probleme bekommen mit dem assert o.O

Ich schau nochmal nach Lösungen, mal sehen was ich finde :)

(Wobei ich sie nich schlechtreden will, also trotzdem danke @antred ;) ^^)
 
Die "andere Variable" muss aber genug Platz haben. Und woher weißt du das vorher? Und wenn du es sicher weißt, warum dann den Umweg gehen?
Wie man eine beliebig lange Zeichenkette einliest, habe ich oben gepostet. Hol sie dir stückchenweise mit fgets() und erweitere das Array falls nötig.
 
Hancock schrieb:
Und das ist gefährlich, weil man implizit auf etwas achten muss, grad Programmieranfängern ist sowas nicht unbedingt klar.

also mit der argumentation ist das programmieren ansich genau so gefählrich wie das benutzten von asserts. bei allem was man macht muss man auf etwas achten und ist programmieranfängern auch nicht unbedingt klar. tautologien for the win.

edit: p.s. ich nutze selbst nie asserts. aber nicht weil sie gefährlich(er) sind. ich finde sie (für mich) nutzlos.
 
genau das selbe wie bei allem auch, wenn man nicht genau weiß was es macht und wofür es da ist.

if( callOnlyOnce() ) {
...
}

...
if( callOnlyOnce() ) {
...
}

statt das ergebnis zu cachen. und weißt du was, damit haben programmieranfänger auch probleme.

edit: im gegensatz zu asserts nutze ich den preprocessor recht intensive (naja sagen wir manchmal intensive). damit lassen sich dinge zsuammenfassen und dem programmier elegant und verständlicher zugänglich machen.
ein einfaches beispiel sind dantestrukturen wie listen zu sogenannten free-listen zu erweitern.
 
Zuletzt bearbeitet:
Hancock schrieb:
Das Problem ist genau das selbe wie bei MAX
Code:
#define MAX(a,b) ((a)<(b)?(b):(a))
MAX(i++,callOnlyOnce());
Plötzlich macht der Code was anderes als dasteht, und das find ich problematisch. (Und zeigt meiner Meinung nach gut, warum man den CPP nur für #includes verwenden sollte.)

Daß man Makros nur sehr sparsam anwenden sollte, steht außer Zweifel. Aber ein paar gerechtfertigte Anwendungsfälle gibt es eben doch. Auf assert zu verzichten, weil man Makros blöd findet, halte ich für groben Unfug.

Und wie kann assert überhaupt nutzlos sein?? Das häufige Überprüfen von Invarianten ist eine der besten Methoden, die Korrektheit seines Codes zu verifizieren. Das klingt für mich ein bißchen nach einer Haltung, die ich von Programmierern kenne, die so von sich überzeugt sind, daß sie tatsächlich meinen, sie bräuchten sich um die Korrekheit ihres Codes keine Gedanken machen, da sie so wie so keine Fehler machen. Ich hatte schon mit solchen Kollegen zu tun ...
 
Hab ich gesagt, dass es nutzlos sei, ich wollt nur sagen, dass es (u.A. für Anfänger) gefährlich sein kann.
Persönlich verwend ich lieber
Code:
#ifndef NDEBUG
cout<<"Value of foo: "<<foo<<endl;
if(foo)
DebugBreak();
#endif
Dann sieht man auch oft, wenn's zwei, drei Schritte früher schon schief ging, wo der Fehler liegt.
 
antred schrieb:
Und wie kann assert überhaupt nutzlos sein?? Das häufige Überprüfen von Invarianten ist eine der besten Methoden, die Korrektheit seines Codes zu verifizieren.
nö ist es nicht.
Das klingt für mich ein bißchen nach einer Haltung, die ich von Programmierern kenne, die so von sich überzeugt sind, daß sie tatsächlich meinen, sie bräuchten sich um die Korrekheit ihres Codes keine Gedanken machen, da sie so wie so keine Fehler machen. Ich hatte schon mit solchen Kollegen zu tun ...

es wäre schön, wenn du bei der sache bleibst statt besserwisserische fantasien zu äussern. wenn du solche kollegen hast ist es schade für dich, aber auf diese weise so etwas einem hier "subtil" unterstellen zu wollen nur weil du dir was anderes nicht vorstellen kannst ist unverschämt. nach "...halte ich führ groben unfug" hättet du spätestens aufhoren sollen.

jetzt aber mal wieder zur sache:
warum meiner erfahrung nach asserts nutzlos sind:
1. invarianten braucht man normallerweise nicht häufig zu überprüfen. das macht man genau einmal beim überprüfen des codes (denn man dazu selbstverständlich immer klein un übersichtlich halten soll).
2, ist es die bessere strategie testfälle zu programmieren um fehler aufzudecken. mit einem assert deckst du nichts auf, wenn du nicht auch den fehlerhaften fall triffst. hast du ein testfallprogramm, so findest du das problem auch so. ohne so etwas hauen asserts meist nur im produktivfall zu, wenn sie da nicht abgeschaltet wären.

natürlich kann man das auch andersrum aufziehen: den code mit asserts vollkleistern und dann verschiedene testdaten reinpumpen (sofern das überhaupt geht) und schaun wo die asserts zu schlagen. die rangehensweise hat meiner erfahrung nach zwei fehler:
1. die meist rel. lokal begränzten invarianten lassen sich nur schwer mit sinvollen testeingabedaten aufdecken, welche für das ganze programm seien müssen (im gegensatz zu tests für einzelne teile)
2. die meisten dinge die man mit asserts "fängt" sieht man sowieso durch einen fehler/exception etc. hochgehen.

ich kann asserts nichts abgewinnen. d.h. aber nicht, dass ich glaube fehlerfrei zu programmieren. wenn du hier konstruktiv diskutieren willst, dann provozier nicht unnötig die leute mit solchen beleidigenden unterstellungen. deine angeblichen erfahrungen mit solchen leuten tuen nichts zur sache hier.

danke!

@hancock: das mit nutzlos bezog sich offensichtlich auf meinen post. ich habe so etwas beahuptet, wobei ich extra anmerkte "für mich".

und zu deinem callonlyonce() beispiel sei noch angemerkt, ich kann auhc zu dem MAX-Makro eine doku schreiben, in der die problematik beschrieben wird. was ichs agen möchte ist, dass es nicht gefährlicher ist für anfänger als fast alles andere auch. generell muss man wissen was man da tut. weiß man es nicht ist es gefährlich und das trifft bei anfängern auf fast alles zu. die argumentation ist so anwendbar auf alles und damit völlig überflüssig.
 
Zuletzt bearbeitet:
Dese schrieb:
es wäre schön, wenn du bei der sache bleibst statt besserwisserische fantasien zu äussern. wenn du solche kollegen hast ist es schade für dich, aber auf diese weise so etwas einem hier "subtil" unterstellen zu wollen nur weil du dir was anderes nicht vorstellen kannst ist unverschämt. nach "...halte ich führ groben unfug" hättet du spätestens aufhoren sollen.

Ok, das war etwas unsachlich, das gebe ich zu. Ich hatte mir am Freitag schon gedacht, daß ich hier vielleicht etwas zu dramatisch aufgetreten bin. Sorry.

Dese schrieb:
jetzt aber mal wieder zur sache:
warum meiner erfahrung nach asserts nutzlos sind:
1. invarianten braucht man normallerweise nicht häufig zu überprüfen. das macht man genau einmal beim überprüfen des codes (denn man dazu selbstverständlich immer klein un übersichtlich halten soll).

Verstehe nicht, was du damit meinst. Was meinst du mit "genau einmal beim überprüfen des codes"? Einen Code-Review??

Dese schrieb:
2, ist es die bessere strategie testfälle zu programmieren um fehler aufzudecken. mit einem assert deckst du nichts auf, wenn du nicht auch den fehlerhaften fall triffst. hast du ein testfallprogramm, so findest du das problem auch so.

Das eine schließt das andere nicht aus. Idealerweise macht man beides, wobei ich es für einen wesentlich größeren Aufwand halte, Testfälle zu schreiben, als assert (oder ähnliche Konstrukte) anzuwenden, und daher das Verhältnis von Aufwand zu Nutzen für den durchschnittlichen Programmierer mit assertions als deutlich besser einschätze.

Dese schrieb:
ohne so etwas hauen asserts meist nur im produktivfall zu, wenn sie da nicht abgeschaltet wären.

Und selbst da sind sie gegenüber der Alternative zu bevorzugen, die da wäre, daß der Code entweder einfach kläglich abschmiert ohne den leisesten Hinweis, woran's lag oder (noch schlimmer) im korrumpierten Zustand scheinbar korrekt weiterläuft, inzwischen aber nichts mehr tut, das man auch nur ansatzweise als korrekt bezeichnen könnte. Bei diversen Anwendungen, an denen ich entwickelt habe, wird assert in einem release-build auf eine std::exception gemapt. Schlägt solch eine assertion in Produktcode zu, wird die exception in der top-level-Funktion gefangen, ins log-File gespuckt (inklusive der verletzten Invariante und der Codezeile / Datei) und das Programm möglichst sauber beendet. Das erleichtet das Finden von Fehlern meiner Meinung nach ungemein.

Dese schrieb:
2. die meisten dinge die man mit asserts "fängt" sieht man sowieso durch einen fehler/exception etc. hochgehen.

Schon, aber häufig erst an einer im Ablauf viel später liegenden Stelle als dort, wo sie verursacht wurde, und um so größer diese Distanz ist, um so schwieriger wird es, auf die eigentliche Fehlerursache zu schließen.
 
Dese schrieb:
natürlich kann man das auch andersrum aufziehen: den code mit asserts vollkleistern und dann verschiedene testdaten reinpumpen (sofern das überhaupt geht) und schaun wo die asserts zu schlagen. die rangehensweise hat meiner erfahrung nach zwei fehler:
1. die meist rel. lokal begränzten invarianten lassen sich nur schwer mit sinvollen testeingabedaten aufdecken, welche für das ganze programm seien müssen (im gegensatz zu tests für einzelne teile)
2. die meisten dinge die man mit asserts "fängt" sieht man sowieso durch einen fehler/exception etc. hochgehen.
Eben nicht. Ich beschäftige mich häufig mit Bildverarbeitung. Wenn du da ein unsinnvollen Wert ins Bild schreibst, stört das erstmal nicht weiter. Erst viel später, wenn ein anderer Algorithmus den fehlerhaften Wert verwendet, geht das ganze möglicherweise hoch bzw. macht sich als Bildfehler bemerkbar und stürzt gar nicht ab (hier sind asserts besonders sinnvoll!). Die lokale Begrenzung hat dann eben den Vorteil, dass der Debugger eben frühzeitig stehen bleibt und der Variableninhalt mir vielleicht etwas über das entstehen des Fehlers sagt. Läuft's weiter, dann taucht die Verursacherfunktion gar nicht mehr im Stacktrace auf und die Variableninhalte, die ursächlich waren, sind lange überschrieben und dann ist großes Raten angesagt. Zumal die Hälfte der Anwendung auf das Bild zugreift, man also auch nicht sagen kann nur Funktion A schreibt überhaupt Daten ins Bild, also kann es nur sie gewesen sein. Mein Programmcode ist deswegen mit Preconditions und Postconditions in Form von asserts vollgekleistert. Unittests eignen sich da eher weniger - ein Bild kann zuviele Möglichkeiten annehmen unterschiedlich auszusehen, deswegen ist es schwer einzelne Funktionen/Module mit sinnvollen/realistischen Daten zu testen. Da ist der einzig realistische Test eben die Anwendung mit einem kompletten Bild durchlaufen zu lassen. Erschwerend kommt hinzu, das man nicht mal eben mit Bleistift und Papier das zu erwartende Ergebnis berechnen kann - schon allein aufgrund der Menge.
Also besonders für numerische Anwendungen halte ich asserts für hochgradig sinnvoll. Nur um irgendwelche Null-Pointer abzufragen, wo zwei Zeilen später der Debugger eh anhalten würde, weil auf den Pointer zugegriffen wird oder Fälle, die nicht so Laufzeitkritisch sind, wo man eh alles im Release Build zur Laufzeit testen kann, da machen asserts natürlich weniger Sinn. Aber anderes Beispiel: Man greift auf einen Vektor zu, mit asserts kann man prima prüfen, ob der Index gültig ist. Bei einem Bild mit einem Megapixel, da sind 1 Million Bereichprüfungen bei jedem einzelnen Pixelzugriff natürlich viel zu langsam, man kann's also nicht einfach ala if(x>=0 && x < size) {..} else {throw ..} prüfen. Dann schreibt man es eben als assert.
 
@geisterfahrer: ich glaub du hast mich nicht ganz verstanden, was aber vermutlich an meiner zu kurz gefassten erklärung bzgl. testfälle liegt.
ich griefe das in meiner antwort zu antred auf.

@antred:
erstmal danke für das verständnis.

zum thema:

für mich stellt sich das so da,w as ihr mit asserts macht:
ihr plflastert an (strategischen puntken) den code mit asserts um zu überprüfen, ob noch das passiert, was ihr erwartet.
das problem ist, dass diese asserts nicht greifen, wenn die eingabedaten nicht zufällig so sind, dass die asserts zu schlagen.

das hauptroblem ist, dass bei der verwendung von asserts man zum einen dazu neigt gutgläubig zu programmieren weil der asserts den patzer ja schon aufdecken wird und zweitens die sonderfälle einzelner code-abschnitte, welche zu problemen führen können so einfach NICHT mehr testbar sin.

ich greife mal das beispiel von geisterfahrer auf: bildbarbeitung.
du hast die bild-rohdaten, die über mehrere filter und algorithmen verarbeitet werden. du hast asserts an verschiedenen stellen in jeder dieser filter.

jetzt sei einer der filter buggy. das fällt dir aber nicht auf, weil die eingabe daten, die du am anfang der kette eingibst, also die bildroh daten auch bei hoher variation nur selten zwischendaten erzeugen (die eingabedaten für den x-ten filter), welche den x-ten filter kaputt gehen lassen.
zu glauben, dass dir mit einem assert hier während der entwicklung irgendetwas auffällt, was man nicht so schon mit etwas nachdenken leicht hätte entdecken können ist naiv.


die alternative nennt sich test-driven-development. und ja, sie macht deutlich mehr arbeit und lohnt sich für den hobby-programmierer oder auch kleinere projekte nicht unbedingt. ich beschreibe hier mal die ideal umsetztung ich bin selbst zu faul mich genau daran zu halten):
man programmiert ZU ERST einen test, welcher für die zu entwickelnde TEILkomponente überprüft, ob ise das tut was sie soll (normale/zufällige eingabe daten + möglichst viele sinnvolle sonderfälle).
DANACH entwickelt man die teilkomponente selbst.

warum der aufwand?
1. ich stelle sicher, dass jede komponente das tut was sie soll
2. ich kann jede einzelne komponente sinnvoll testen ohne die dazu passenden ursprungseingabedaten bestimmen zu müssen, die zu den gewünschten zwischendaten führen, die ich für genau die komponente bracuhe, die ich testen will (was nämlich oft kaum möglich ist).
3. ich kann automatisierte tests laufen lassen und somit feststellen, wenn in der zwischenzeit (z.b. von anderen teammitlgiedern) veränderter code mitlerweile mit anderen teilen inkompatibel geworden ist etc.

natürlich kann man hier asserts immer noch dazu nehmen. nach meiner erfahrung nach aber sind sie für mich (ich betone noch einmal für mich) völlig überflüssig.


mit asserts sehe ich wo eine invariante innerhalb eines langen komplexen programms verletzt wird. schön, aber so weit sollte man es nie kommen lassen. man sollte lieber:
1. einzelne kleine code-teile auf ihre invarianten überprüfen (das geht IMMER lokal, denn wenn A die invariante erhölt, B es tut und auch C, dann tut dies auch immer A*B*C).
2. wenn der fehler tatsächlich in der kombination der komponenten liegt, dann nützen mir die asserts auch nicht mehr, denn dann fällt der fehler erst auf, wenn das ergebnis der kombination vorliegt und mehr kann man dann auch trotz asserts nicht sagen.

also entweder ich überprüfe die invarianten lokale für alle komponenten, dann geht das besser mit tests für die komponenten oder aber ich mahc es erst dann, wenn alles schief geht, dann helfen mir invarianten-checkende asserts auch nicht mehr.

edit: aber wie gesagt, wenn euch asserts helfen, dann ist das ja schön. für mich sind sie total überflüssig. sie geben mir keine information, die ich nicht anders sinnvoller und vor allem frühzeitiger bekommen kann.

edit: programmieren mit assersts ist für mich prgrammieren auf gut glück, die asserts werden den fehler schon finden.... hoffentlich noch während der entwicklung weil im produktivsystem sind sie ja aus ;)
so was kann ich mir nicht leisten.

ich muss sicherstellen, dass jede funktion, jede komponente richtig arbeitet und das geht NICHT über asserts sondern nur über tests und testfälle für die komponenten.
Ergänzung ()

geisterfahrer schrieb:
Also besonders für numerische Anwendungen halte ich asserts für hochgradig sinnvoll. Nur um irgendwelche Null-Pointer abzufragen, wo zwei Zeilen später der Debugger eh anhalten würde, weil auf den Pointer zugegriffen wird oder Fälle, die nicht so Laufzeitkritisch sind, wo man eh alles im Release Build zur Laufzeit testen kann, da machen asserts natürlich weniger Sinn.
asserts sind im relase-build aus, z.m. sollten sie das sein. sit das bei euch nicht so? Oo
Aber anderes Beispiel: Man greift auf einen Vektor zu, mit asserts kann man prima prüfen, ob der Index gültig ist. Bei einem Bild mit einem Megapixel, da sind 1 Million Bereichprüfungen bei jedem einzelnen Pixelzugriff natürlich viel zu langsam, man kann's also nicht einfach ala if(x>=0 && x < size) {..} else {throw ..} prüfen. Dann schreibt man es eben als assert.

schon mal was von conditional-break-points gehört? ist viel besser als dem debugger mit asserts im code zu "helfen". ganz besonders dann, wenn man c/c++ programmiert. da sollte man den code möglichst nicht ändern, falls der fehler an pufferüberläufen oder ähnlichem liegt. da kann ein printf mehr oder weniger and der richtigen stelle alles ändern oder auch nur eine variablen deklaration.
 
Zuletzt bearbeitet:
Dese schrieb:
ich muss sicherstellen, dass jede funktion, jede komponente richtig arbeitet und das geht NICHT über asserts sondern nur über tests und testfälle für die komponenten.
Hab nicht das Gegenteil behauptet.

Dese schrieb:
asserts sind im relase-build aus, z.m. sollten sie das sein. sit das bei euch nicht so? Oo
Klar ist das so. Bei nochmaligen Lesen meines Textes weiß ich nicht so recht, welcher Teil das impliziert haben soll, das bei mir im Release Build die Dinger an wären...

Dese schrieb:
schon mal was von conditional-break-points gehört? ist viel besser als dem debugger mit asserts im code zu "helfen". ganz besonders dann, wenn man c/c++ programmiert. da sollte man den code möglichst nicht ändern, falls der fehler an pufferüberläufen oder ähnlichem liegt. da kann ein printf mehr oder weniger and der richtigen stelle alles ändern oder auch nur eine variablen deklaration.
Conditional Breakpoints sind schön und gut, aber nicht dauerhaft. Mir geht es insbesondere auch um Preconditions einer Funktion. Wenn die fehlerfreie(!) Funktion aber irgendwann durch Änderungen an ganz anderer Stelle mit falschen Argumenten aufgerufen wird, hat man das dann eben schwarz auf weiß: Die Funktion bricht schon mit dem assert vor jeglichem eigentlichen Programmcode ab, was ansonsten evtl durchgelaufen wäre und nur noch mehr Mist produziert hätte(*).
Mir geht es bei Asserts primär darum, Fehler zu lokalisieren, wenn welche auftreten, nicht um sicherzustellen, ob die Funktion korrekt arbeitet. Ein Unittest sagt mir nur, ob eine Funktion/Modul fehlschlug, mit asserts sehe ich möglicherweise auch wo. Unittest können keinerlei Invarianten innerhalb einer Funktion prüfen und wenn eine sinnvolles Testen einer einzelnen Funktion nicht möglich ist, möglicherweise noch gröber. Es geht also keineswegs um asserts vs unittest, sondern eben beide haben ihre Daseinsberechtigung.

*Meinetwegen ruft Funktion A (gerade in Entwicklung) Funktion B auf (die getestet und korrekt ist). Man stellt fest, Funktion A hat insgesamt Mist gebaut (meinetwegen auch per Unittest). Die Frage lautet nun: wo. Wenn Funktion A nun Funktion B mit falschen Argumenten aufruft, sieht man das eben sofort, wenn die Preconditions verletzt werden. Der Debugger hält an der Stelle an, man kann sehen, wie es zum fehlerbehafteten Aufruf kam. Man hat also eine Stelle, wo man die Fehlersuche in Funktion A anfangen kann - ohne wüsste man nur das sie fehlerhaft ist und hätte keinerlei Anhaltspunkte wo der Fehler liegt.
 
ich kann dein beispiel nicht nachvollziehen, also dessen nützlichkeit.

1. wenn funktion A so groß ist, dass du ein assert brauchst um ne geignete einstiegstelle zur fehlersuche zu finden, dann ist sie ZU groß.
2. warum hat Funktion A nicht auch schon einen Test (so wie in deinem beipsiel funktion B)? den test schreibt man BEVOR man die zu testende funktion entwickelt, oder wenigstens parallel.
3. natürlich kann ein unittest invarianten prüfen und er kann so fein sein wie man möchte. wenn man es auf die spitze treiben will, kann man mit einem unittest jede einzelne code-zeile separat testen. ALLES was du mit einem assert testest geht auch mit einem unit-test (nicht das es unbedingt sinnvoll ist, aber deine einschränkungen zu den unittests kann ich nicht teilen).

aber um das mal jetzt nicht ausarten zu lassen:
ich habe nichts gegen asserts im allgemeinen. das habe ich auch nicht geschrieben. ich sagte für mich sind sie meist nutzlos.
es gab durch aus situationen, wo ich mal zu einem assert gegriffen habe (naja, assert im eigenbau aber darauf kommt es ja nicht an), aber das war weil ich keinen debugger hatte. allerdings habe ich in solchen situationen eher nur auf debug-meldungen zugegriffen. mehr als ausführliche prints waren nie nötig. gleich ein assert zu nehmen kann ich nichts abgewinnen.

ist halt meine erfahrung und meinung. wenn du da andere hast, dann weißt du sie ja vieleicht besser einzusetzten als ich (nein, das meine ich nicht sarkastisch). den letzten assert habe ich vor über 10 jahren geschrieben.
 
Dese schrieb:
1. wenn funktion A so groß ist, dass du ein assert brauchst um ne geignete einstiegstelle zur fehlersuche zu finden, dann ist sie ZU groß.
Zu pauschal.
Dese schrieb:
2. warum hat Funktion A nicht auch schon einen Test (so wie in deinem beipsiel funktion B)? den test schreibt man BEVOR man die zu testende funktion entwickelt, oder wenigstens parallel.
Schrieb ich doch selbst: Der Fehler flog durch den Unittest von Funktion A auf...

Mal etwas konkreter:
Code:
int funktionA()
{
	int sum = 0;
	for(int i =0; i < 1000; i++)
	{
		if(i != 500)
			sum += funktionB(i);
		else
			sum += funktionB(-1);
	}
	return sum;
}

int funktionB(int param)
{
	assert(param >= 0);
	if(param >= 0)
		return 0;
	else
		return -50000; //precondition wurde verletzt, funktion stürzt nicht ab, sondern liefert nur unsinnigen Wert
}

Jetzt schlägt also der Unittest von A fehl, weil Gesamtergebnis negativ, was nicht hätte sein dürfen, Unittest B ist erfolgreich, sofern man nur gültige Daten übergibt.
Jetzt hab ich aber keine Ahnung wo, ohne den Assert sehe ich nur, das die Gesamtsumme negativ ist. Mit dem Assert hält der Debugger in Funktion B an und ich sehe im Stacktrace sofort, dass das der Aufrufer etwas vergeigt hat bei i=500. Der zusätzliche Hinweis, das der Fehler bei i = 500 auftrat ist Gold wert und vereinfacht die Sache ernorm. Und lang ist die Funktion auch nicht, sie läuft nur sehr lange.

Um's evtl vorweg zu nehmen:
Code:
int funktionB(int param)
{
	if(param >= 0)
		return 0;
	else
		throw;
}
Das ist nicht immer eine Alternative, weil auch im Release Build aktiv und damit definitv zu langsam, wenn es eine Funktion ist, die mehrere Millionen mal aufgerufen wird.
 
Ich dachte, bei einem Unittest soll man auch falschen Daten angeben, um auch zu erkennen, ob die Funktion richtig darauf reagiert...
(BTW: Wenn du schon >=0 testest, dann mach doch param gleich zu unsigned, dann klatscht dir der Compiler unsinnigen Code um die Ohren.)

Und zu der zweiten Variante, haste das mal in Compiler reingetan? Möglicherweise wird dir dein throw wegoptimiert... (Oder in Verbindung mit funktionA direkt geworfen).
 
Hancock schrieb:
Ich dachte, bei einem Unittest soll man auch falschen Daten angeben, um auch zu erkennen, ob die Funktion richtig darauf reagiert...
Wie ich schrieb: Wenn du Funktion schnell sein muss, ist es nicht sinnvoll, das die Funktion auf falsche Aufrufparameter prüft (im Release-Build). Wenn das Ergebnis unbestimmt ist macht es herzlich wenig Sinn, das zu überprüfen. Wenn man natürlich die zweite Variante implementiert, sollte man natürlich überprüfen, ob korrekterweise eine Exception geworfen wurde. Deswegen eindeutig: Jein!, lässt sich also nicht verallgemeinern. Bei mir lautet bei einigen performancekritischen Funktionen die Devise, das der Aufrufer für korrekte Parameter zu sorgen hat.

Hancock schrieb:
(BTW: Wenn du schon >=0 testest, dann mach doch param gleich zu unsigned, dann klatscht dir der Compiler unsinnigen Code um die Ohren.)

Und zu der zweiten Variante, haste das mal in Compiler reingetan? Möglicherweise wird dir dein throw wegoptimiert... (Oder in Verbindung mit funktionA direkt geworfen).
Meine Güte, das ich ist doch nur ein Minimalbeispiel für's Forum. Du kannst davon ausgehen, das der falsche Parameter in echten Anwendungen nicht statisch schon im Programmcode drinnesteht, so das zur Kompilierzeit schon feststeht, ob eine Exception geworfen werden muss oder nicht. Genauso könnte die Funktion nur gültiges für >= -1 liefern... Das ändert doch überhaupt nichts an der Frage asserts oder nicht.
 
also ich kann verstehen, dass du in funktion B weder ne exceptio noch ausgiebige validierung der paramter machen willst, aus performance gründen halt.

aber wenn du B schon per unittest validiert hast, dann brauchst du dein assert nicht mehr. du weißt dadurch schon, dass A die funktoin B falsch aufrufen muss oder z.m. vor dem aufruf von B was schiefgeht. und mehr sagt dir dein assert auch nicht.

du hast genau null informationsgewinn durch das assert. du siehst durch den unittest, dass A was falsches produziert, du weißt, dass B richtig arbeitet. na was sagt uns das?

p.s. @hancock. eigentlich sollte man auch auf negative beispiele testen, das geht aber leider zum einen nicht immer und zum anderen nur bedingt. zum einen dann nicht, wenn man aus performance gründen keinerlei behandlung ungültiger eingaben in einer fuktion haben will (dann kann man sich den test sparen, weil es garanteirt schief gehen wird) und zum anderen, weil man kaum alle möglichen fälle abdecken kann.

edit: geisterfahrer, ehrlich, ich verstehe warum du das so machst. und es spricht auch nichts dagegen. ich führ meinen teil habe bisher so immer leicht die stelle finden können an der es schiefgeht oder per debugger den rest. mit dem assert weißt du auch nur irgendwo da oder davor ist es schiefgegangen. genauer gehts auch damit nicht.
und bei geeigneter aufteilung der methoden und der tests kann ich das im allgemeinen auch ohne asserts genauso (un)preäzise orten.
jeder wie er's mag ;)
Ergänzung ()

so und jetzt laßt mich gefälligst ohne asserts weiter programmieren :P

leute ehrlich, ich wollt hier deswegen keine riesen diskussion vom zaunbrechen. asserts sind hilfsmittel. nicht jeder emfpindet ein hilfsmittel gleich mützlich wie andere. deswegen schrieb ich auch ausdrücklich für mich nutzlos.
 
Zuletzt bearbeitet:
Dese schrieb:
aber wenn du B schon per unittest validiert hast, dann brauchst du dein assert nicht mehr. du weißt dadurch schon, dass A die funktoin B falsch aufrufen muss oder z.m. vor dem aufruf von B was schiefgeht. und mehr sagt dir dein assert auch nicht.

du hast genau null informationsgewinn durch das assert. du siehst durch den unittest, dass A was falsches produziert, du weißt, dass B richtig arbeitet. na was sagt uns das?
Mit dem assert sehe ich das mindestens bei i=500 was schiefgelaufen ist und kann dann nachvollziehen, wie es zu dem fehlerhaften Aufruf gekommen ist, weil ich noch den Stack des Aufrufers einsehen kann. Wenn ich nur per Unittest das Fehlverhalten von A feststelle, kann ich nur darauf schließen das mindestens irgendeine der 1000 Iterationen schiefgelaufen sein muss, aber keinerlei Anhaltspunkt welche der tausend. Klar, ich weiß das ein Fehler in A ist, aber mit dem Debugger sämtliche tausend Iterationen im Einzelschrittverfahren durchmachen um den Fehler beobachten zu können ist gelinde gesagt etwas aufwändig, insbesondere, wenn wie im Beispiel der Fehler in der 500ten Iteration erstmalig auftritt. Wenn man erst am Ende der Funktion A mit dem Debuggen beginnt, sind sämtliche Informationen, wie es zum fehlerhaften Aufruf von B kam längst überschrieben (kamen ja nachfolgend weitere 500 Iterationen mit richtigen Aufrufparametern) und wenn der Schleifenkörper problembedingt etwas komplexer ist, dann ist das nicht durch scharfes hinsehen, wie bei dem Beispiel ja problemlos möglich ist, getan. Wie gesagt, die Information das der Fehler bei i=500 auftritt ist es mir Wert, asserts in den Quellcode zu schreiben. Mit einem Unittest von Funktion A bekommt man diese Information nämlich nicht.
Klar, man kann den for-Schleifen Körper in eine extra Funktion auslagern, so das man sieht das dann der Unittest für diese Funktion für den Parameter i=500 fehlschlägt, aber jetzt jeden einzelnen Schleifenkörper in eine separate Funktion auslagern fände ich übertrieben. Wenn man das konsequent verfolgt hat man dann bald nur noch einzeilige Funktionen und ewig lange Parameterlisten mit Variablen die zuvor nur in einer Funktion lokal auftauchten, so das dann irgendwann das Unittests schreiben zur Qual wird. Hinzu kommen Performanceprobleme, wenn problembedingt Rückgabewerte rumkopiert werden müssen. Da heißt es abwägen, bei meinen Problemstellungen ist das Ergebnis der Abwägung oft eben eine eher komplexe for-Schleife. Das Problem lässt sich nicht immer beliebig an die Testwünsche anpassen.

Und wie gesagt, halte ich asserts besonders für numerische Programme geeignet, also wo sehr viele Daten in Schleifen verarbeitet werden. Zumal dann es vorkommt, das man einen Schleifenkörper nicht weiter in Unterfunktionen aufbröseln will, weil es eine zusammenhängende (mathematische) Formel ist und sonst der logischen Aufteilung entgegensteht. Es gibt Programme, die ich geschrieben habe, da ist nicht ein assert drin, weil es tatsächlich Fälle gibt, wo es wenig Sinn macht - sie sind eben kein Allheilmittel. Besonders bei sehr Kontrollstrukturlastigen finde ich ist dies der Fall. Hätte die Funktion A nämlich keine ewig langlaufende Schleife, wäre man ja tatsächlich mit dem Debugger in einer handvoll Schritten da durch. Kann also gut sein, das bei deiner Art von Programmen, sie wenig nutzen, aber das sie keinerlei Zusatzinformationen liefern in bestimmten Fällen ist einfach nicht richtig.
 
geisterfahrer schrieb:
Und wie gesagt, halte ich asserts besonders für numerische Programme geeignet, also wo sehr viele Daten in Schleifen verarbeitet werden.
ich glaube hier liegt der hase im pfeffer begraben.
ich stimme dir hier zu, obowhl ich hier dennoch nie asserts genutzt habe, aber konstrukte, die im grunde nichts anderes sind. d.h. ob ich ein assert nutze oder 2 zeilen code, die bedingt debuging ausgaben machen ist kein wirklicher unterschied.

der hauptgrund für mich hier ein eigenkonstrukt statt assert zu nehmen war eigentlich fast immer, dass ich es einfach schneller von der hand ging. bevor ich nach schaue, wie asserts in der geraden verwendeten programmiersprache genau zu benutzten sind, war das if-statement+print auch schon hingeklatscht.

edit: darf ich unsere einigkeit so zusammenfassen?:
asserts ODER ähnliche konstrukte sind nützlich, wenn man einen fehlerfall oder invariante innerhalb numerischen kalkulationen (soll heißen, kruzen berechnungen, die aber sehr oft per schleifen wiederholt werden). natürlich auch anders wo, aber in diesem fall besonders.
aber man kann asserts eben leicht mit anderen konstrukten nachbilden.
 
Zuletzt bearbeitet:
Zurück
Oben