2010-03-09 6 views
11

Manchmal muss ich Code schreiben, der abwechselnd Dinge ausführt und nach Fehlerbedingungen sucht (z. B. eine Bibliotheksfunktion aufrufen, ihren Rückgabewert überprüfen, weitermachen). Dies führt häufig zu lange Läufe, wo die eigentliche Arbeit wird in den Bedingungen geschieht, wenn Aussagen, wieGuter c-Stil, wenn viele Rückgabewerte überprüft werden

if(! (data = (big_struct *) malloc(sizeof(*data)))){ 
    //report allocation error 
} else if(init_big_struct(data)){ 
    //handle initialization error 
} else ... 

Wie ihr schreiben, um diese Art von Code? Ich habe einige Style Guides überprüft, aber sie scheinen sich mehr mit Variablennamen und Leerzeichen zu beschäftigen.

Links zu Style Guides sind willkommen.

Edit: für den Fall, dass es nicht klar ist, bin ich unzufrieden mit der Lesbarkeit dieses Stils und auf der Suche nach etwas Besserem.

+1

Während Sie dabei sind, würde ich persönlich die '(big_struct *) - Cast verlassen, es sei denn, Sie müssen einen C++ - Compiler verwenden, um diesen Code zu kompilieren. Es ist ein strittiges Problem, aber wenn Sie keine C++ - Anforderungen haben, denke ich, dass es am besten ist, es auszulassen. –

Antwort

15

Obwohl es schmerzt, es zu sagen, könnte dies ein Fall für die nie-populäre goto sein. Hier ist ein Link, den ich auf dem Thema gefunden habe: http://eli.thegreenplace.net/2009/04/27/using-goto-for-error-handling-in-c/

+0

Wenn Sie in Ihrem Code "goto" nicht sehen können, können Sie ihn immer verschleiern. http://stackoverflow.com/questions/2314066/do-whilefalse – jschmier

+1

+1 Mit goto ist immer noch der beste Weg in dieser schrecklichen Sprache. – Tronic

+1

ja - dies ist eine gute Übung für C-Code (in C++ - Code verwenden Ausnahmen und RAII). setze Ressourcen ptrs auf NULL; Setzen Sie dann, wenn Sie haben, und haben Sie einen gemeinsamen Ausgangspunkt, der freigibt, wenn! NULL. Einziger Nachteil ist, dass Sie wirklich alle Ihre Ressourcen-Variablen in den oberen Bereich der Funktion setzen (ich bevorzuge so lokal wie möglich zu deklarieren) – pm100

13

Ich schreibe in der Regel, dass Code auf diese Weise:

data = (big_struct *) malloc(sizeof(*data)); 
if(!data){ 
    //report allocation error 
    return ...; 
} 

err = init_big_struct(data); 
if(err){ 
    //handle initialization error 
    return ...; 
} 

... 

Auf diese Weise vermeiden ich Funktionen innerhalb wenn und die Debug ruft einfacher, weil Sie die Rückgabewerte überprüfen.

3

Verwenden Sie nicht assert in Produktionscode.
Im Debug-Modus, assert sollte nie für etwas verwendet werden, die tatsächlich (wie malloc Rückkehr NULL) passieren kann, sondern es sollte in den unmöglichen Fällen verwendet werden (wie Array-Index außerhalb der Grenzen in C)

Read this post for more.

2

Eine Methode, die ich zu großer Wirkung verwendet habe, ist die von W. Richard Stevens in Unix Network Programming (Code ist herunterladbar here. Für gemeinsame Funktionen, die er erwartet, um die ganze Zeit erfolgreich zu sein, und keinen Rückgriff auf einen Fehler hat, wickelt er sie , mit einem Großbuchstaben (Code vertikal komprimiert):

void * Malloc(size_t size) { 
    void *ptr; 
    if ((ptr = malloc(size)) == NULL) 
     err_sys("malloc error"); 
    return(ptr); 
} 

err_sys Hier wird der Fehler angezeigt und führt dann eine exit(1). Auf diese Weise können Sie einfach Malloc anrufen und wissen, dass bei einem Problem ein Fehler auftritt.

UNP weiterhin das einzige Buch, das ich habe, wo ich denke, der Autor hat Code, der die Rückgabewerte aller Funktionen überprüft, die es möglich ist, zu scheitern. Jedes andere Buch sagt "Sie sollten die Rückgabewerte überprüfen, aber wir lassen das für Sie später tun".

+2

Es sollte angemerkt werden, dass, obwohl eine solche Lösung oft gut für ein eigenständiges Programm ist, ist es sehr schlechte Idee um Fehler in Bibliotheken so zu behandeln - sie sollten nie unerwartet abbrechen. –

0

Ich neige dazu,

  • Delegate Fehlerfunktionen Wrapper Überprüfung (wie Stevens)
  • Bei einem Fehler simulieren Ausnahmen longjmp verwenden. (Ich benutze eigentlich Dave Hanson C Interfaces and Implementations Ausnahmen zu simulieren.)

Eine weitere Option ist Don Knuth verwenden literate programming den Fehlerbehandlungscode oder eine andere Art von Prä-Prozessor zu verwalten.Diese Option ist nur verfügbar, wenn Sie die Regeln für Ihren Shop festlegen :-)

0

Die einzige Gruppierungseigenschaft von Code wie diesem ist, dass es einfach eine extern auferlegte Sequenz gibt, der er folgen muss. Deshalb setzen Sie diese Zuordnungen in eine Funktion, aber das ist eine sehr schwache Gemeinsamkeit. Warum einige Leute empfehlen, den Umfang der Vorteile von geschachtelten ifs zu verlassen, ist jenseits meines Verständnisses. Sie versuchen effektiv, Lippenstift auf ein Schwein zu setzen (keine Beleidigung beabsichtigt) - die Natur des Codes wird nie etwas sauberes ergeben, das Beste, was Sie tun können, ist, die Compilerhilfe zu verwenden, um (Wartungs) -Fehler zu fangen. Bleib bei der IMHO.

PS: wenn ich Sie noch nicht überzeugt habe: Wie wird die Goto-Lösung aussehen, wenn Sie ternäre Entscheidungen treffen müssen? Die If's werden sicherlich hässlicher, aber die Goto's ???

Verwandte Themen