Definizione dei codici di errore

5

Stiamo progettando un framework di gestione degli errori per una libreria crittografica scritta in C

L'approccio che stiamo adottando è che relativamente pochi errori vengono propagati all'utente poiché nella maggior parte dei casi non può fare nulla su di essi (eccezione notevole: errori di validazione dei parametri. Ovviamente si dice all'utente se una chiamata è andata a buon fine. d anche creare voci di registro per l'analisi dei guasti.) In breve, solo perché abbiamo una condizione di errore da qualche parte all'interno della libreria, non significa che abbiamo bisogno di un codice di errore pubblico (rivolto all'utente) per questo.

Inoltre, dalle esperienze passate pensiamo che una porzione significativa di condizioni di errore che richiedono codici di errore riguardano aree di codice molto ristrette, spesso accade che un particolare errore sia restituito solo da (o impostato da) una funzione.

Pertanto vorremmo definire i codici di errore al livello più basso possibile. Ad esempio, se solo una funzione può restituire / impostare un particolare codice di errore, definiremo quel codice nel file .h in cui è stato dichiarato il prototipo della funzione.

Tuttavia, in tal caso potremmo ottenere conflitti nel codice di errore: lo stesso valore del codice di errore per errori diversi. Qualcuno può proporre un approccio elegante per evitare tali conflitti? O almeno un meccanismo automatizzato per verificare tali conflitti (che possono quindi essere risolti a mano)?

    
posta malenkiy_scot 09.09.2014 - 17:32
fonte

2 risposte

4

we would define that code in the .h file where the function prototype is declared.

Mi raccomando di non avere nulla per ridurre lo spazio per potenziali conflitti di numerazione.

Utilizzare invece un file di intestazione comune che fornisce i codici di errore per le applicazioni client e server. In alternativa, il file client può essere semplicemente un sottoinsieme del file del codice di errore del server.

All'interno del file di intestazione comune, ciascuna area principale dell'applicazione riceverà una sequenza di numeri di errore. E dall'interno di ciascuna area principale, puoi assegnare sottoinsiemi di intervalli di codici di errore ai moduli all'interno di quel livello.

Ad esempio, supponiamo di avere un gestore di sessione, una logica aziendale e un livello di accesso al database nell'applicazione server. Il tuo file di intestazione potrebbe essere suddiviso in questo modo:

/*
 * our error.h file 
 */
/* Common Errors 0 - 99 */
#define SUCCESS 0
#define GENERIC_ERROR 1
/* Session Manager errors 100 - 199 */
    /* Login issues 100 - 110 */
#define BAD_PASSWORD 101
    /* session issues 120 - 125 */
    /* other session issues 150 - 162 */
#define SOMETHING_ELSE 150
/* Business logic errors 200 - 299 */

/* Database errors 300 - 399 */
#define INVALID_CONNECTION 300

Il vantaggio di questo approccio è che riduce lo spazio complessivo in cui possono verificarsi conflitti nella numerazione. Il potenziale conflitto è limitato alle aree in cui due o più sviluppatori lavorano contemporaneamente.

Avendo un file di intestazione di errore comune, gli sviluppatori possono verificare il file in base alle necessità per creare un nuovo errore e assicurarsi che stiano reclamando un numero inutilizzato in quel momento.

Le potenziali insidie con questo approccio sono quando gli sviluppatori non impegnano frequentemente la loro copia locale dell'intestazione dell'errore. Ma questo è un problema di processo che di solito si risolve una volta che questi sviluppatori hanno dovuto affrontarlo alcune volte. E dal momento che si riferiscono al numero di errore tramite #define non è un grosso cambiamento.

Un altro trabocchetto è quando giudichi male l'intervallo richiesto per un livello o sottomodulo. Il modo più semplice per evitarlo è pre-allocare intervalli molto ampi per ogni livello e sottomodulo. E da lì, dovresti essere in grado di tagliare da un sottomodulo per dare una maggiore distanza ad un altro. E non c'è nulla che dice che gli intervalli devono essere contigui.

    
risposta data 09.09.2014 - 17:51
fonte
2

Raccomando di utilizzare un file di codice di errore comune, esattamente come @ GlenH7, ma vorrei anche raccomandare di scrivere funzioni o moduli autonomi che non richiedono affatto il file di errore globale. Ad esempio, se una funzione di "connessione" può fallire (o meno), restituire un indicatore booleano. Il chiamante di quella funzione può decidere di mappare il valore di ritorno booleano su una costante globale, ma non sulla funzione di connessione stessa:

  success = connect(parameters);
  if(!success)
      return INVALID_CONNECTION;

  success = check_password(paramaters);
  if(!success)
      return BAD_PASSWORD;

  //...
  return SUCCESS;

Per software più grandi formati da molti moduli o librerie diverse, magari sviluppati da diversi team, è spesso meglio evitare qualsiasi codice di errore globale e utilizzare solo codici di errore locali per modulo o per libreria. Per distinguerli, ad esempio, in un file di registro centrale, è sempre necessario aggiungere il nome del modulo o qualche tipo di ID modulo al codice di errore. È possibile imporre l'utilizzo di questi due valori progettando le API del logger in questo modo - con una funzione di "log" che prevede l'identificazione di un modulo e un codice di errore come parametri, non solo un codice di errore. Se devi davvero passare i codici di errore attorno al tuo programma in modo globalmente distinguibile, puoi creare una struct "ErrorCode", con due attributi "ModuleID" e "LocalErrorCode". In questo modo puoi evitare la necessità di avere codici di errore globali.

    
risposta data 09.09.2014 - 18:41
fonte

Leggi altre domande sui tag