2017-01-19 3 views
1

Lasst uns sagen, dass ich eine Reihe von Fehlercodes haben in meiner Anwendung header.h wie:Elegante Abbildung von C Fehler definiert reiht

#define SOMETHING_WENT_WRONG -1 
#define SOLAR_FLARE_DECTECTED -2 
#define ANTS_IN_YOUR_CPU  -3 

kehre ich diese als int aus verschiedenen API-Funktionen. Ich möchte eine saubere Möglichkeit bieten, eine Funktion anzubieten, die der Benutzer aufrufen kann, um diese auf aussagekräftigere Fehlermeldungen abzubilden, während der Header kurz gehalten wird.

Das heißt, während ich könnte immer so etwas tun:

const char *getErrorMessage(int errCode) { 
    switch (errCode) { 
    case SOMETHING_WENT_WRONG: 
    return "Something bad happened, but I don't know more than that"; 
    case SOLAR_FLARE_DECTECTED: 
    return "A solar flare, rather than programmer error, has caused a malfunction"; 
    case ANTS_IN_YOUR_CPU: 
    return "Ants have nested in your CPU, causing all ALU functions to fail"; 
    default: 
    return "I heard you like errors in your error handling. So ..."; 
    } 
} 

ich wirklich zweimal die Vervielfältigung unter Angabe der Fehler Makro vermeiden will (DRY) und mit der Definition und die Fehlerzeichenfolge in zwei verschiedene Orte (was es nicht offensichtlich macht, dass diejenigen, die einen Fehlercode hinzufügen, auch die Fehlerfunktion aktualisieren müssen).

So suche ich nach einem Ansatz, der nur 1 Zeile (ish) pro Fehlercode verwendet - der Makroname, int Fehlercode und Nachricht alle zusammen.

Bonuspunkte, wenn ich die Fehlerzeichenfolge auslassen kann und die Fehlerzeichenfolge nur den Namen des Zeichenfolgenmakros haben (z. B. für den ersten Fehler).

Ich mache mir keine Sorgen über die Nachschlageleistung, also ist es zum Beispiel gut, ein Array zu erstellen und in der Lookup-Funktion durchzusehen.

+4

[Xmacros] (http://www.drdobbs.com/the-new-c-x-macros/184401387) kann den Trick machen, obwohl sie einige (nicht zu) tiefe C wissen müssen, um zu verstehen. – StoryTeller

+0

Warum geben Sie die Zeichenfolgenliterale im Makroformat nicht selbst zurück? NULL zeigt keinen Fehler an. Die Leistung ist gleich. – 2501

+0

@ 2501 - interessant, aber es ist einfach kein typisches Fehlerbehandlungs-Idiom in C. Es hat Probleme, zB wenn der Aufrufer den Fehlercode überprüfen möchte (sie müssten 'strcmp' anstelle von' == 'verwenden , und je nachdem, wie die Strings verwendet wurden, kann ich den Stringtxt in Zukunft möglicherweise nicht ändern.Wenn ich '#define SOME_ERROR 'noch immer ein Fehlermuster verwende, kann der Linker dies tun oder auch nicht Kombiniere die identischen Strings, die linkerabhängiges Verhalten verursachen können, wenn Leute die Zeiger vergleichen, usw. – SODIMM

Antwort

4

Als ich zum ersten Mal in dieser Ausgabe kam, machte ich es so, dass für jeden Makro, ich _STR Makro daneben hinzugefügt:

#define SOMETHING_WENT_WRONG  -1 
#define SOMETHING_WENT_WRONG_STR "Something went wrong" 

#define SOLAR_FLARE_DECTECTED -2 
#define SOLAR_FLARE_DECTECTED_STR "Solar flare detected" 

#define ANTS_IN_YOUR_CPU  -3 
#define ANTS_IN_YOUR_CPU_STR "Ants in your CPU" 

const char *errorstr; 
int errorno; 
#define SET_ERROR(e) errorno = e; errorstr = e##_STR; 

So kann ich einfach SET_ERROR (ANTS_IN_YOUR_CPU) und die ErrorNo nennen könnte und String würde erledigt werden.

+0

Sie können einen nicht ganzzahligen Wert nicht einschalten und Fälle müssen auch Konstanten sein. – 2501

+0

Auf einer 64-Bit-Maschine würden diese Zeigerwerte als Rückgabewerte von 'main()' nicht verwendet werden. –

+0

@ 2501 Du hast absolut recht, ich habe diesen Teil nur zusammen genommen. –

4
enum errs { 
    __ERR_NONE, 
    SOMETHING_WENT_WRONG, 
    SOLAR_FLARE_DECTECTED, 
    ANTS_IN_YOUR_CPU, 
    __ERR_MAX, 
}; 
static const char * const errorstrings[__ERR_MAX] = { 
    "__ERR_NONE", 
    "Something bad happened, but I don't know more than that", 
    "A solar flare, rather than programmer error, has caused a malfunction", 
    "Ants have nested in your CPU, causing all ALU functions to fail", 
}; 

//index the error strings by the error value 
printf("%s\n", errorstrings[SOMETHING_WENT_WRONG]); // Something bad happened, but I don't know more than that 

Sie können eine ziemlich saubere Konvertierung unter Verwendung der Ganzzahlen als Indizes für die Fehlerzeichenfolgen durchführen.

+0

Dieser Ansatz scheint vernünftig zu sein, obwohl er den Nachteil hat, den Fehlercode und die Nachricht nicht nebeneinander zu legen und die beiden Strukturen durch "Augenschein" synchron zu halten - dh wenn Sie einen Fehler in die Liste von 100 müssen Sie das Array genau an der richtigen Stelle aktualisieren. Ich schätze, Sie können eine Kompilierungs-Assertion hinzufügen, die mindestens das 'errorstrings'-Array und die' errs 'haben die gleiche Größe, um verpasste Additionen zu erfassen. – SODIMM

-2

Verwenden Sie eine Hashtabelle, in der Fehlercodes als Schlüssel und Stringzeiger als Werte verwendet werden. Schlechte Neuigkeiten sind, dass Sie es zur Laufzeit manuell ausfüllen müssen, und Sie können alle Fehlercodes verwenden. Signierte oder sogar Float-Nummern.

+0

C verfügt nicht über Hashtabellen, und Sie benötigen keine für Ganzzahlindizes. Ein Array von Strings wird ausreichen. – DyZ

+0

Jemand erlaubt Ihnen nicht, Ihre eigene Hash-Tabelle zu definieren? Und wie verwenden Sie negative Zahlen als Indizes? Und wie werden Sie alle synchronisieren, wenn Sie einen Code aus dem Array entfernen? – Ariel

+0

(1) Worum geht es? (2) 'array [-code]'; (3) Behalte die Slots einfach unbenutzt. – DyZ