2009-08-28 13 views
9

Questo è molto specifico, e un po 'difficile da spiegare, e molto probabilmente impossibile, ma qui va.Rileva l'utilizzo della macro? (errno)

Voglio implementare errno.h >. (. Il mio progetto hobby sta attuando un libreria standard C)

Il modo ingenuo per andare a questo proposito è:

// in <errno.h> 
extern int errno; 

// in some .c file 
int errno = 0; 

Questo funziona. Ma ha uno svantaggio: se viene chiamata una funzione di libreria matematica, è sempre deve interrogare lo stato dell'unità FPU dopo l'esecuzione per impostare errno come appropriato. Ciò blocca la FPU in applicazioni matematiche.

Il C norma appoggia valutazione pigra di errno rendendolo una macro invece:

int * __errno(); 
#define errno *__errno() 

questo modo, errno è solo "set" quando il suo valore è effettivamente richiesto:

// "__errno()" returns the location of the current errno value, 
// the "errno" macro turns it into a value. 
x = errno; 

Dato un po 'di logica nel resto della libreria, lo stato della FPU deve essere interrogato solo se l'ultima funzione della libreria chiamata era in realtà uno utilizzando FPU, e il valore di errno è attualmente richiesto.

Finora tutto è a posto. Ma è il contrario che mi sta dando il mal di testa:

errno = 0; 

Il valore di errno non è richiesto a tutti. Ma lo __errno() non lo sa e interrogherà lo stato della FPU se l'ultima funzione della libreria chiamata stava utilizzando la FPU.

In questo momento non vedo un modo per evitare che (vale a dire, hanno la macro errno o la funzione __errno() in qualche modo funzionare in modo diverso a seconda che essi sono utilizzati per la sinistra o la destra dell'operatore di assegnazione), e sono quasi contento di accettare questo.

Ma forse qualcuno di voi SO'ers ha un'idea geniale?

risposta

4

Nessuna idea brillante qui, ma è possibile implementare errno tramite chiamate di funzione per rendere possibili le implementazioni thread-safe della libreria standard. Non credo che l'interrogazione del FPU pigramente è una buona idea: Come pensate di evitare le eventuali incoerenze in situazioni come questa:

  • set errno
  • ops in virgola mobile che ha fissato le bandiere di errore
  • ottenere errno
  • get flags

In caso di chiamata a __errno() cancellare le bandiere o no?

Secondo lo standard, se lo errno deve essere impostato o meno dalle funzioni matematiche è determinato dal valore di math_errhandling (in particolare, math_errhandling & MATH_ERRNO).

Quello che vorrei fare è rendere l'errore di segnalazione opzionale tramite le direttive del preprocessore e consentire al programmatore di impostare il valore di math_errhandling in fase di compilazione. Ciò significherebbe che le funzioni matematiche non possono essere compilate staticamente in anticipo ma devono risiedere in un'intestazione, il che potrebbe comunque essere una buona idea consentire ai compilatori senza ottimizzazioni in tempo di collegamento di integrare tali funzioni.

2

Quello che hai qui è un'analisi abbastanza buona del perché l'intero meccanismo errno è così insoddisfacente. È possibile trovare un'analisi simile anche nella "Biblioteca standard C di Kernighan".

La forma funzionale di errno è inoltre necessaria per implementazioni thread-safe, in cui thread diversi hanno valori di errore separati a cui si accede tramite un thread specifico errno.

La macro avrebbe meritato parentesi intorno ad esso per la sicurezza:

#define errno (*__errno()) 
1

Più un commento di una risposta, ma senza formattazione del codice non sarebbe comprensibile.

Se si controlla pigro il flag FPU, come si dovrebbe avere il comportamento corretto qui (le funzioni matematiche sono speciali in quanto sono garantiti di non modificare errno quando non ci sono problemi)?

errno = 0; 
x = acos(y); 
z = <exp>; 
if (errno != 0) { 
    /* can't come here even if y is a valid argument but <exp> modified the flags if it didn't call any functions */ 
}