2012-03-29 5 views
2

Ich bin ein C-Programmierer im Gange gerade erst zu fühlen, dass ich einige Dinge richtig mache. Da ich an Sprachen auf höherer Ebene gewöhnt bin (wie C# und Python), vermisse ich meine Ausnahmen sehr.Welche Fehlerprüfung sollte ich innerhalb dieser Funktion durchführen?

Das Folgende ist eine Funktion, die ich geschrieben habe und derzeit verwende, um in Streams X Anzahl der Zeichen zu sehen.

Welche Fehlerprüfung konnte innerhalb dieser Funktion durchgeführt werden, um sicherzustellen, dass ein Programm nicht gebremst wird?

#include <stdio.h> 
#include <string.h> 

#include "speek.h" 

void speek(char *peek, size_t len, FILE *stream) { 

    int i; 

    for (i = 0; i < len; i++) { 
     peek[i] = fgetc(stream); 
     if (feof(stream) || i >= len - 1) { 
     // Null terminate the string if stream is EOF or requested number 
     // of characters has already been fetched. 
     peek[i] = '\0'; 
     break; 
     } 
    } 

    for (i = strlen(peek); i >= 0; i--) { 
     ungetc(peek[i], stream); 
    } 
} 
+0

Dies ist * die * schwierigste Teil C: Sie im Voraus entscheiden, wie Sie wollen prüfen, und melden Sie Fehler, und Sie haben weder Ausnahmen, noch Stapelabwickeln. Bei E/A-Fehlern, von denen Sie nicht wiederherstellen können, schlage ich vor, das Programm einfach mit einer Fehlermeldung zu stoppen. Für die Frage per se kann jede E/A-Funktion jederzeit fehlschlagen (zB stellen Sie sich vor, die Datei befindet sich auf einem USB-Stick und Sie entfernen sie, während Ihr Programm läuft), also sollten Sie überprüfen, ob * jede * -Funktion korrekt ausgeführt wurde . –

Antwort

1

Ich würde immer die Datei * überprüfen, wie ich Zeichen lese.

Ich denke, es ist eine stilistische Sache, aber ich würde nicht etwas, was ich normalerweise beabsichtige, innerhalb der Schleife passieren.

Schließlich sollte eine erfolgreich gelesene Zeichenfolge immer durch ein '\ 0' beendet werden. Ich bin oft verwirrt darüber, was zu tun ist, wenn ein Fehler aufgetreten ist. Wenn ich weiß, wofür die Funktion ist, könnte ich normalerweise wählen.

So, Ihren Stil der Dateiprüfung mit:

void speek(char *peek, size_t len, FILE *stream) { 

    int i; 
    for (i = 0; i < len-1 && !feof(stream); i++) { 
     peek[i] = fgetc(stream); 
    } 

    peek[i] = '\0'; 

    for (i = strlen(peek)-1; i >= 0; i--) { 
     if (ungetc(peek[i], stream) != peek[i]) { 
     break; // I'd return an error, but function is void 
     } 
    } 
} 

Wenn dies mehr als ein schnelles Experiment ist, oder ich war dies für andere zu schreiben, könnte ich assert verwendet Parameter zu überprüfen (ja, ich weiß, ich weiß immer noch (c = getc (...)), ich bin alt)

#include <assert.h> 

int speek(char *peek, size_t len, FILE *stream) { 
    assert(peek != NULL); 
    assert(len > 0); /* Could 0 be okay? */ 
    assert(stream != NULL && !ferror(stream)); 

    int i; 
    int c; 
    for (i = 0; i < len-1 && (c=getc(stream)) != EOF; i++) { 
     peek[i] = c; 
    } 

    peek[i] = '\0'; 

    if (ferror(stream)) return -1; 

    for (int j = i-1; j >= 0; j--) { 
     if (ungetc(peek[j], stream) != peek[j]) { 
     return -1; 
     } 
    } 
    return i; /* I like to return something useful */ 
} 

Edit: ich habe versucht, das Original zu spiegeln, aber es ist nicht so, wie ich es tun würde, so dass ich schließlich gab auf und schrieb, was ich eigentlich schreiben wollte.

Edit2: ... Aber ich habe einen Fehler gemacht. Der korrekte Ansatz besteht darin, zu überprüfen, ob Platz für das Zeichen vorhanden ist, bevor es gelesen wird. Do!

Einfache Testprogramm:

int main (int argc, const char * argv[]) { 
    char line0[100]; 
    int n0 = speek(line0, 4, stdin); 

    fprintf(stderr, "%d '%s'\n", n0, line0); 

    char line1[100]; 
    int n1 = speek(line1, 8, stdin); 

    fprintf(stderr, "%d '%s'\n", n1, line1); 

    return 0; 
} 

eine Datei Da nur abcefghij enthält, gibt

3 'abc' 
7 'abcdefg' 
+0

Assert ist hier vollkommen in Ordnung, da fehlgeschlagene Assertion einen Fehler im Programm anzeigt. –

+1

@Alexandre C - Ja. Ich denke, insbesondere wenn Menschen C lernen, ist Assert eine nützliche Gewohnheit; "Bugs zu Tode behaupten". Es gibt den Dateinamen und die Zeilennummer des Fehlers an, wodurch das Debugging beschleunigt wird. Es kann der Anruferfehler sein, dass diese Behauptungen fehlschlagen, aber beim Lernen ist es "all mein eigener Code", es ist immer noch ein Fehler, der sehr frustrierend sein kann. – gbulmer

+0

10 Vielen Dank für Ihre ausgezeichnete Antwort, obwohl hier etwas fehlt. Ihre Funktion, und wahrscheinlich auch meine ursprüngliche, zieht einen Char zu viel, ohne ihn zurückzuschieben. Ich habe es gelöst, aber ich fürchte, es ist nicht mehr so ​​elegant. Wie würdest du es getan haben? – frklft

0

zu Hinzufügen was @Thiruvalluvar bemerkt hat,

  1. Wenn die Datei eine leere peek würde nur ein NULL Zeichen enthalten. i = strlen(peek) wird 0 zurückgeben, aber Sie treten immer noch in die Schleife ein, wie Sie i>=0 haben und versuchen, ein Zeichen in den Stream zurückzuschieben, den Sie nie von dort bekommen haben. Der gleiche Fall ergibt sich auch dann, wenn len Null ist!

  2. Noch eins ist, dass Sie nicht den Rückgabewert von ungetc überwachen. Es könnte EOF bei einem Fehler zurückgeben.

0

Neben der Zeiger für NULL Überprüfung und if (len > 0) rate ich würde Sie überprüfen, ob die FILE * gültig ist. Sie können es tun, indem Sie es an fileno() übergeben und prüfen, ob es einen anderen Wert als -1 zurückgibt.

1

Wie Pavan Manjunath angibt, haben Sie Fehler in Ihrem Programm. Mindestens eine andere, die ich sofort sehen kann, ist, dass Sie keine NUL-Zeichen in der Datei behandeln: Am Ende der Funktion verwenden Sie strlen, die nur Ihren Stich bis zum ersten NUL-Byte misst, was nicht unbedingt ist so viele Bytes, wie Sie tatsächlich gelesen haben.

Aber das ist Bugs im Allgemeinen. Sie haben speziell nach Fehlerüberprüfungen gefragt. Niemand hat den wichtigsten Ort erwähnt, um nach Fehlern zu suchen: wenn beim Lesen der Datei ein Fehler auftritt. Sie sollten den Rückgabewert von fgetc() für EOF wie in seiner Manpage beschrieben (bevorzugt) überprüfen oder die Funktion ferror() danach verwenden, um zu testen, ob beim Lesen der Datei ein Fehler aufgetreten ist.

Überprüfung peek und stream für NULL wie von Thiruvalluvar vorgeschlagen ist defensiv, aber ich würde nicht notwendig sagen. Diese sollten nicht NULL sein. Wenn dies der Fall ist, ist Ihr Anrufer schuld, nicht Ihr.

+1

* Jede * E/A-Operation kann fehlschlagen. Sie sollten überprüfen, dass * jeder * E/A-Funktionsaufruf wie vorgesehen funktioniert hat. –

Verwandte Themen