Weiterer Diskussionsbetrag: Eine Funktion, die nichts tut, wenn ein Null-Zeiger übergeben wird, ist aus meiner Sicht wertlos: [[Code] void optionale_funktion( char*p ) { if( p ) { /* hier erst passiert das, was den Lebenszweck dieser Funktion ausmacht */ } } ] (Dieser Gedanke ist vielleicht eine Hilfe bei der Entscheidung optional oder nicht für einen als Zeiger übergebenen Parameter; wenn die Funktion zu einem "Nichtstuer" verkommt, ist die Optionalität kontraproduktiv.) In C++ kann man für obligatorische Parameter Referenzen verwenden. In C könnte man Null-Zeiger bei obligatorischen Parameter übergehen, das Verhalten ist hierbei ja meist hochdefiniert. Die nächstbessere Wahl wäre assert aber das Programm ist hiermit natürlich nicht zu retten (aber man bekommt vieleicht mit, was passiert ist). Erst exception-artige Mittel könnten den Ausfall (Neustart) auf das Subsystem beschränken; andererseits liegt hier mit großer Gewissheit ein Programmfehler vor, ein erforderlicher Parameter darf nicht null sein, wie lange auch immer ein solches System weiterlaufen kann, die Software hat diesen Fehler und muss prinzipiell ausgewechselt werden. WolfPeuker |
KategorieCee KategorieProgrammierStil |
KategorieC KategorieCee KategorieProgrammierStil |
Um das Ganze an einem Beispiel zu sehen, hier eine simple Implementation der Standard-C-Funktion strcpy:
|
Wenn ein fehlerhafter Pointer oder NULL übergeben wird, dann greift das Programm beim Dereferenzieren mit hoher Wahrscheinlichkeit auf Speicherbereiche zu, auf die ihm der Zugriff verboten ist und es kommt zu einer Zugriffsverletzung.
Die Funktion macht im einzelnen folgende Annahmen über die Inputparameter:
|
oder die nicht-NULL-Vorbedingungen durch assert geprüft werden:
|
Dabei ist absichtlich die Rückgabe des dest-Parameters weggelassen (er spielt keine Rolle und steht nur deshalb im strcpy-Beispiel, damit das Interface nicht vom Standard abweicht).
Man könnte also auch noch ein "nacktes" strcpy ergänzen:
|
Die selbstgestellte Aufgabe ist es nun, alle Vor- und Nachteile der einzelnen Implementationsvarianten (vor allem im Bezug auf mögliche Fehlersituationen) im Detail zu betrachten und zu bewerten. Was soll oder kann das bringen? Allgemeine Erkenntnisse über die Ausgestaltung von Interfaces, denn diese simple Funktion steht natürlich exemplarisch für die Mehrzahl der Funktionen in C, da ja fast jede Funktion Zeiger bzw. Objekt-Parameter in Form von Zeigern übernimmt. -- HelmutLeitner
"Null Als Input Parameter" wird auch in IstAssertSinnvoll/UndWieWeitSollEsGetriebenWerden diskutiert.
Siehe auch AssertionVermeidung --kg
Ich habe früher mal gedacht, besser wäre ein Programmierstil, der Abstürze möglichst verhindert, also wenn null übergeben wird, besser nichts machen, obwohl ein null-Zeiger an dieser Stelle nicht vorgesehen ist. Aber so verschleppt man Fehler! Sie führen nicht zum Abbruch, werden so nicht bemerkt. Seit ich Java kenne, habe ich dieses Paradigma gelassen. Weil ein falscher null-Zeiger als Exception mit Stack-Trace sehr gut erkennbar ist, und diese Exception im Gesamtkontext gut aufgefangen werden kann. So ist's richtiger, ist meine Erfahrung.
In diesem Zusammenhang halte ich auch nichts von assertion, sondern von guter try-catch-throw-Verwendung. Wir hatten auf Arbeit früher ein System, das ist bei einem Fehler sofort auf Gesamt-Halt gegangen, der Prozess stand. Als Inbetriebsetzer hatte man die Möglichkeit, in diesem eingefrorenem Zustand alle Werte anzuschauen. So war das gedacht. Aber das "H" passierte auch beispielsweise bei einem Underflow-Fehler (wenn ein double-Wert ganz nahe an der 0 lag, kleiner 2 hoch -38, und dann auf float gecastet wurde) oder solche Situationen. Das ganze war in C zu programmieren.
Mit try-catch-throw ist es aber nun möglich, einen Abbruch-fehler in einem Modul zu verkraften. Das Modul wird aborted, aber nicht gleich die ganze Steuerung. Das Modul lässt sich (mit evtl anderen Eingangsdaten) neu starten. Daher meine ich - zurück zum Thema - ist ein Angst-null-Test nicht mehr nötig. HartmutSchorrig.
|
(Dieser Gedanke ist vielleicht eine Hilfe bei der Entscheidung optional oder nicht für einen als Zeiger übergebenen Parameter; wenn die Funktion zu einem "Nichtstuer" verkommt, ist die Optionalität kontraproduktiv.)
In C++ kann man für obligatorische Parameter Referenzen verwenden. In C könnte man Null-Zeiger bei obligatorischen Parameter übergehen, das Verhalten ist hierbei ja meist hochdefiniert. Die nächstbessere Wahl wäre assert aber das Programm ist hiermit natürlich nicht zu retten (aber man bekommt vieleicht mit, was passiert ist). Erst exception-artige Mittel könnten den Ausfall (Neustart) auf das Subsystem beschränken; andererseits liegt hier mit großer Gewissheit ein Programmfehler vor, ein erforderlicher Parameter darf nicht null sein, wie lange auch immer ein solches System weiterlaufen kann, die Software hat diesen Fehler und muss prinzipiell ausgewechselt werden. WolfPeuker