Datum:
Hallo, ich hätte da eine Frage bezüglich der Fehlerbehandlung in C. Ich kenne die Konzepte der Fehlerbehandlung ( return, longjmp, lokaler Fehlerindex ). Was mir aber bei diesen fehlt ist, dass ich nicht weiss wer den Fehler verursacht hat (also welche Funktion). Bsp:
#include <stdlib.h>
#include <stdio.h>
int errorCode = 0;
char* errorFile = "\0";
char* errorLine = "\0";
void (*ErrorHandler) (void);
ErrorHandler errorHandler = NULL;
#define error(a) errorCode = a; errorFile = __FILE__; errorLine = __LINE__; errorHandler()
void doSomething(int count)
{
...
error(12);
}
void handler()
{
/* Fehlerausgabe etc. */
}
int main()
{
errorHandler(handler);
doSomething(45);
...
return 0;
}
|
Ich hoffe es funktioniert auch, kann es jetzt nicht testen (grad kein Compiler zur Verfügung). Das Problem dieser Methode ist (oder eigentlich alle die ich kenne), dass ich keine Informationen, wer der Verursacher ist, bekomme. Sie kann mir zwar sagen, dass in doSomething() der Fehler aufgetreten ist und was für einer, allerdings erfahre ich nicht, dass es in Wirklichkeit main() ist. Also wenn ein falscher übergabe Wert übergeben wurde. Ich hoffe es ist verständlich. Bei C# sieht man gleich den ganzen Aufrufbaum der Funktionen (bzw. Methoden). Kurz und knapp wie macht ihr das? Gut bei kleinen Programmen ist die einfache schon in Ordnung, aber bei größeren Projekten, wo eine Funktion 1000 aufgerufen wird. Vielen Dank für eure Antworten :).
Datum:
Suche mal das 'assert' commando im stdlib documentation, ich denke das ist genau was nu brauchst
Datum:
Öhm, wie wäre es mir errno per Hand setzen und dann mit perror() und strerror() ausgeben?
Datum:
er möchte einen CallStack! Man müsste es selber Programmieren, in jeder funktion ruft man ein Makro auf was den funktionsnamen und eventeull noch die Parameter auf den "Stack" legt und diese am ende auch wieder entfernt. Und Genau das ist schon ein Problem denn man muss immer dafür sorgen das es wieder entfernt wird wenn die funktion verlassen wird. C++ und den Destruktoren geht das etwas eleganter.
Datum:
Aber soweit ich weiss gibt assert Datei und Linie von dort aus wo auch assert aufgerufen wurde, also in doSomething(). Naja perror() und strerror() bringt mir nicht so viel, wenn ich den Fehler in einem Fenster anzeige.
Datum:
Genau das ist es was PeterII angesprochen hat. Allerdings ist es ziemlich aufwendig, man müsste in jeder Funktion (wie main()) den Funktionsnamen etc. setzen. Geht das nicht eleganter oder muss ich mich damit zufrieden geben? Wie sucht man dann den Fehler bei einem großen Programm, wo doSomething() 1000 aufgerufen wird? Raten und schauen ob man Recht hat?
Datum:
Wenn du jeder möglichen Fehlerstelle eine eindeutige Nummer zuornest, die du zurückgibst, dann weisst du zumindest wo genau der Fehler aufgetreten ist, auch wenn du keinen Call stack hast. Wir haben da im allgemeinen ein eigenes Fehlermodul mit einer h Datei in der alle Fehlernummern als Konstante definiert sind. Das Problem ist bei allen Fehlerkonzepten, auch bei "try .. catch" etc. man muss sich konsequent an sein System halten.
Datum:
Christopher C. schrieb: > Allerdings ist es > ziemlich aufwendig, man müsste in jeder Funktion (wie main()) den > Funktionsnamen etc. setzen. könnte man sogar per script mache, so aufwendig ist das nicht. > Geht das nicht eleganter oder muss ich mich > damit zufrieden geben? in C nicht. > Wie sucht man dann den Fehler bei einem großen > Programm, wo doSomething() 1000 aufgerufen wird? Raten und schauen ob > man Recht hat? mit dem Debugger - dort einfach den CallStack anzeigen. (in der hoffnung das niemand der STack überschrieben hat)
Datum:
M.W. gibt es sowohl in der glibc als auch bei VS Bibliotheksfunktionen, um den Call Stack zu holen - natürlich nicht portabel,
Datum:
Christopher C. schrieb: > Wie sucht man dann den Fehler bei einem großen > Programm, wo doSomething() 1000 aufgerufen wird? Raten und schauen ob > man Recht hat? Problem nachstellen und debuggen Oder einschaltbares Tracing mit unterschiedlichen Leveln. Dazu gibts auch entsprechende Bibliotheken, Ich programmiere allerdings in den letzten Jahren nur Java und wir benutzen log4j. Zu den eindeutigen fehlernummern: Bei größeren Projekten übersichtlicher wird es wenn man die Nummer aus einer Modulnr und der Fehlernummer zusammensetzt. Also z.b. Modul 34 und Fehler 132 ergibt dann "034132".
Datum:
Christopher C. schrieb: > Naja perror() und strerror() bringt mir nicht so viel, wenn ich den > Fehler in einem Fenster anzeige. Bei perror kannst du ja noch zuätzlichen Erklärtext einfügen. Also könntest du das noch mit
__LINE__ __FILE__ |
usw aufpeppen. http://openbook.galileocomputing.de/c_von_a_bis_z/... Kann aber auch sein, dass ich gar blicke was du wirklich willst. ;-)
Datum:
Danke so viele Rückmeldungen ;). Der Trick mit der Modul-ID und der Callstack gefällt mir schon mal gut. Es müsste eine Plattformunabhängige Lösung sein, weshalb der Callstack rausfliegt, schade :(.
Datum:
Weil das alles in der Rubrik PC-PRogrammierung steht, gehe ich davon aus, daß es nicht um MC geht. Dann frage ich mich aber, wieso man auf C besteht und nicht C++ nimmt. Da kann man mit Ausnahmen viel schönere Sachen bauen.
Datum:
Die beste Vorgehensweise zur Fehlerbehebung bzw. -Vermeidung im Zusammenhang mit C: Schreibe den Programm mit einer RICHTIGEN Programmiersprache und nicht mit diesem nutzlosen Frickler-Zeugs für langhaarige Kellerkinder mit schweren sozialen Störungen.
Datum:
(Rechner, auf denen C: zu finden ist, meide ich auch.) Magst du deine Störungen nicht mal woanders ausleben, oder musst du jetzt jeden Thread, wo du nichts Intelligentes zu sagen hast, vollmüllen?
Datum:
Ach egbert. Halt dich einfach raus, wenn du keine Ahnung hast. In Zukunft werd ich deine unqualifizierten Meldungen kommentarlos löschen. C ist eben nichts für Leute, die eine Tante brauchen, die mit ihnen Lulu geht.
Datum:
Karl Heinz Buchegger schrieb: > In Zukunft werd ich deine unqualifizierten Meldungen kommentarlos > löschen. Warum erst in Zukunft?
Datum:
Udo Schmitt schrieb: > Karl Heinz Buchegger schrieb: >> In Zukunft werd ich deine unqualifizierten Meldungen kommentarlos >> löschen. > Warum erst in Zukunft? Auch wieder wahr. Aber erst mal soll er wissen, dass er sich vergebliche Tipparbeit macht.
Datum:
> Ich hoffe es ist verständlich. Ist es. > Bei C# sieht man gleich den ganzen Aufrufbaum der Funktionen > (bzw. Methoden). Siehst du im Debugger normalerweise auch. Wenn das Problem beim Kunden auftritt, sieht die Sache aber anders aus. Es gibt Runtime Systeme, die in solchen Fällen einen kompletten Stackdump machen. Den kann der Kunde schicken und dann kann man den analysieren. Manchmal hilft das sogar was. Denn in den meisten Fällen, ist der interessante Teil nicht der, das das Programm abgeschmiert ist, sondern der Weg wie es dazu gekommen ist. In einem realen Programm hat eine Division durch 0 eine Vorgeschichte, die nicht selten in irgendeiner vorhergehenden Benutzereingabe ihre Ursache hat (und das muss nicht notwendigerweise die letzte gewesen sein). Dort steckt irgendwo das eigentliche Problem. Das ist das eine. Das andere ist: Ja C# kann das. Aber um welchen Preis? Da wo C Programme noch einen kleinen schnuckeligen Speicherfootprint haben, machen sich C# Programme im Speicher breit. C wurde eben in den 60-er Jahren nach dem Muster entworfen: You don't get for what you didn't ask. Das Runtime System macht nur das, was absolut notwendig ist um die Funktion zu erfüllen. Willst du mehr, dann musst du dir das selber machen. Hat Nachteile, hat aber auch Vorteile: Du "erbst" nicht riesige Bibliotheken mit einem unbedachten Funktionsaufruf.
Datum:
Die GNU-C-Bibliothek stellt eine backtrace()-Funktion bereit: http://www.gnu.org/software/libc/manual/html_node/...
Datum:
> Wie sucht man dann den Fehler bei einem großen > Programm, wo doSomething() 1000 aufgerufen wird? Letzten Endes gibts nur eines: testen, testen, testen. In Idealfall ist nicht der Programmierer selbst der Tester, sondern du hast eigene Leute dafür. Wenn die spitz kriegen "Operation X ist im Zusammenhang Y nicht sinnvoll", dann testen die 100-erte Variationen von X im Zusammenhang Y, alles was ihnen einfällt, um dein Programm zum Absturz zu bringen (und genau das ist das, was Programmierer normalerweise nicht tun) und sagen dir hinterher, wie sie den Absturz geschafft haben. assert wurde ja schon angesprochen. Ist ein hilfreiches Werkzeug in der Debug-Phase, weil eine Funktion im Debugger laut 'Hilfe hier' schreit, weil irgendwelche Dinge nicht so sind, wie sie eigentlich sein sollten. Damit kriegt der Entwickler schon in der Entwicklungsphase eine Menge Probleme in den Griff, die sonst erst beim Kunden auftreten würden und dort ungleich mehr Schaden anrichten.
Datum:
Karl Heinz Buchegger schrieb: > Letzten Endes gibts nur eines: testen, testen, testen. nein hilft leider nicht. Wenn man z.b. in eine Datei schreiben will und das write einen Fehler liefert "fehler beim schreiben" dann hilft einem das überhaupt nicht weiter. Die Write funktion selber kennt auch nur das fiele-handle damit kann man auch nicht anfangen. In so einen Fall braucht man für eine sinnvolle fehleranalyse einen CallStack wo man sieht in welchen zusammenhang etwas in die Datei geschrieben weden soll. Und darin sehe ich wirklich ein Problem in C/C++ - die Fehlersuche ist viel komplizierter als in C# oder Java. Ich hatte es mal versucht mit Makros und C++ hinzubekommen, das man eine CallStack bekommt - ja es geht aber es ist ein zusätzlicher Aufwand und man muss sich zwingen es wirklich überall einzusetzen.
Datum:
Peter II schrieb: > Und darin sehe ich wirklich ein Problem in C/C++ - die Fehlersuche ist > viel komplizierter als in C# oder Java. Das stimmt, mit einem Stacktrace hat man schnell einen Anhaltspunkt wo man mit der Suche anfangen muss. Und wenn dann die Exception noch ein "Null-Pointer", eine "Array out of Bounds", eine "Data not numeric" oder "Data truncation at Table, Row" liefert, dann hat man auch den Grund und kann davon ausgehend zurückschauen. Das hilft nicht immer aber sehr oft. Man spart sich nach meinen Erfahrungen bai 30 -50% von Kundenproblemen das zuhause nachstellen, bzw. kann das Problem gezielt und schnller nachstellen. Aber was auf einem modernen PC kein Problem ist (große Runtime, viele DLLs) ist auf einem µC oder auch einem ARM wieder was ganz anderes. Genauso wie Geschwindigkeit wenn es mal wirklich darauf ankommt.