2010-09-07 11 views
5

Ho una domanda di design semplice (?).C: errore di lancio sul controllo dei parametri o lasciare che colpisca il ventilatore?

Sto scrivendo un programma semplice, che ha un paio di funzioni simili a queste.

float foo (float* m,size_t n){ 

    float result; 
    //do some calculations, for example a sum 


    return result/n; 
} 

Ho un paio di domande su questo, senza alcuna intenzione di ri aprendo qualche guerra santa.

Devo aggiungere un controllo di integrità sul n? In caso affermativo, come dovrei informare il chiamante?

Tornando -1 sembra strano su galleggianti;

float foo(float *m,size_t n){ 
    if (n == 0) return -1f 

    ... 
    } 

mia altra opzione è un parametro out

float foo(float *m,size_t n, int *error){ 

     if (n==0){ 
      *error = 1; 
      return 0f; 
     } 
     ... 
} 

aggiornamento

Questo è tipo di un programma giocattolo, solo cercando di praticare alcune cose. La domanda supera questo fatto. Forse dovrei riformulare su "come gestire gli errori senza eccezioni (OOP)".

Anche considerando il test n prima di effettuare la chiamata, ma non mi piace tanto.

Qualche idea? Grazie in anticipo.

+0

Potrebbe essere utile ascoltare ulteriori informazioni sull'ambiente delle funzioni. Esistono in un corpo di codice con pratiche di verifica degli errori o in cui il codice di terze parti ha determinate aspettative? È un progetto giocattolo autonomo? – TSomKes

+1

@TsomKes ha aggiornato la mia domanda. – Tom

risposta

6

immagino la vostra opzione out parameter è un buon compromesso. Ma immagino che sarebbe meglio il contrario. Utilizzare il parametro out per ottenere il risultato e il valore restituito per indicare lo stato della chiamata. Ti piace questa

int foo(float *m, size_t n, float* result) 
{ 
    if(someFailureCondition) 
    return ERROR; // ERROR being an error integer 
    // else 
    // do some calculation 
    // set your result 
    return NO_ERROR; // NO_ERROR being an integer 
} 

Edit: Il valore restituito può essere più dettagliato per indicare lo stato attuale del parametro fuori. Guarda il commento di Jamesdlin!

+0

Grazie, non l'ho considerato. Sembra più elegante. – Tom

+1

Preferisco questo stile anche per il controllo degli errori di runtime, ma dovresti inoltre indicare esplicitamente (come parte del contratto della funzione) quale stato dei parametri di output sono in errore (ad esempio sono in uno stato indefinito, non sono stati toccati o impostati ad un certo valore specifico). – jamesdlin

2

Se -1 non viene restituito dalla funzione in ogni caso, restituire con tutti i valori -1. Ma se passare n = 0 non interromperà la funzione, allora non è veramente necessario. Suppongo che n sia la dimensione dell'array m.

La gestione degli errori è una questione di preferenza. OpenGL gestisce gli errori restituendo un codice di errore (-1 o altro) quando una funzione fallisce. Il codice di errore viene restituito tramite la chiamata a GetLastError() (o qualcosa del genere). Questa sembra una soluzione ideale per la gestione degli errori.

+0

sì, n è il numero di elementi in m. – Tom

1

Ci sono valori speciali virgola mobile è possibile utilizzare se si vuole - per esempio, se l'implementazione in virgola mobile supporta tranquilla NaN (Not-a-Number) quindi è possibile utilizzare la macro NAN da math.h:

#include <math.h> 
float foo(float *m,size_t n) 
{ 
    if (n == 0) return NAN; 

    ... 
} 
+0

Considerato, ma non è il caso del "non fare nulla"? – Tom

+0

Non sono sicuro di cosa intendi. Dovrebbe essere simile al tuo caso '-1f', tranne per il fatto che si prova con' isnan() ', e si propagherà attraverso calcoli a virgola mobile successivi. – caf

1

È necessario consentire ai chiamanti di sapere qual è la semantica della propria funzione documentando chiaramente il codice.

Qual è il contratto per la vostra funzione? Se ai chiamanti viene richiesto di non passare 0 per n, è necessario spiegarlo e la funzione deve utilizzare assert per verificare che tali requisiti siano soddisfatti.Errori logici dovrebbero essere rilevati in anticipo e tali guasti dovrebbero essere il più spettacolari possibile.

Ora, se si sta scrivendo codice per una libreria che sarà consumato da altri sviluppatori e sono preoccupati che la gente compilare con assert disabilitato, allora è ragionevole che si combinano con un modo di rottura più morbida che è sempre abilitata:

if (n == 0) 
{ 
    assert(0); 
    return NAN; /* Or return some error code */ 
}