2009-05-04 9 views
18

Devo utilizzare C per un progetto e sto pensando di utilizzare longjmp/setjmp per la gestione degli errori poiché penso che sarà molto più facile gestire l'errore in un punto centrale rispetto ai codici di ritorno. Gradirei se ci fossero alcuni indizi su come farlo.Quali sono alcuni "buoni" modi per utilizzare longjmp/setjmp per la gestione degli errori C?

Sono particolarmente interessato alla pulizia delle risorse eseguita correttamente se si verifica un errore di questo tipo.

Inoltre, come posso gestire gli errori che comportano l'utilizzo di programmi multi-thread?

Ancora meglio, esiste una libreria C già esistente per la gestione di errori/eccezioni?

risposta

5

Ho sempre e solo trovato uno uso per setjmp()/longjmp() e non ha avuto a che fare con la gestione degli errori.

Non c'è davvero bisogno di usarlo per questo poiché può sempre essere rifattorizzato in qualcosa di più facile da seguire. L'uso di setjmp()/longjmp() è molto simile a goto in quanto può essere facilmente abusato. Tutto ciò che rende il tuo codice meno leggibile è una cattiva idea in generale. Nota che non sto dicendo che sono intrinsecamente cattivi, solo che possono portare a codice cattivo più facile delle alternative.

FWIW, l'unico posto in cui erano inestimabili era un progetto che facevo nei primi giorni del settore (MS-DOS 6). Sono riuscito a mettere insieme una libreria multi-threading cooperativa utilizzando Turbo C che utilizzava queste funzioni in una funzione yield() per cambiare attività.

Sono abbastanza certo di non averli toccati (o ne ho avuto bisogno) da quei giorni.

+1

+1 Li ho usati solo una volta: in una protezione da copia per un gioco DOS. Ho usato longjmp invece della normale ramificazione per confondere i cracker. Questo ha funzionato in qualche modo perché il codice generato sembra diverso da un ramo. :-) –

+0

Divertente coincidenza: ho costruito un cooperatore automatico ca. 1985 usando setjmp()/longjmp() per girare su una stazione di lavoro SGI sotto il loro sapore unix del giorno. Ha funzionato come un fascino. Poiché è stato utilizzato per l'animazione, includeva un rendering che sincronizzava tutti i thread con l'interruzione verticale del sistema video. Non li ho usati direttamente da allora, comunque. – RBerteig

5

Symbian ha implementato il suo meccanismo Leave in termini di longjmp() e questo serve come una buona passeggiata tra tutte le cose che dovete fare.

Symbian dispone di un "cleanup stack" globale che consente di eseguire il pop e il pop delle cose che si desidera eliminare in caso di un salto. Questa è l'alternativa manuale allo stack automatico che si svolge durante il compilatore C++ quando viene lanciata un'eccezione C++.

Symbian aveva "imbracature" che sarebbe saltato fuori; questi potrebbero essere annidati.

(Symbian più recentemente lo ha reimplementato in termini di eccezioni C++, ma l'interfaccia rimane invariata).

Tutti insieme, penso che le eccezioni C++ corrette siano meno inclini agli errori di codifica e molto più veloci di quelle del proprio equivalente C.

(I compilatori C++ moderni sono molto bravi a eccezioni 'zero overhead' quando non vengono lanciati, ad esempio: longjmp() deve memorizzare lo stato di tutti i registri e tali anche quando il salto non viene più eseguito, quindi può fondamentalmente mai essere veloce come eccezioni.)

Utilizzare C++ come C migliore, dove si adottano solo eccezioni e RAII, sarebbe un buon percorso se si utilizza longjmp() per l'emulazione di eccezioni essere tentazione per voi.

+0

Per favore, usa il nome corretto: longjmp/setjmp, non 'longjump'. –

+0

grazie per l'informazione. Tuttavia, la domanda è specifica dell'uso di C non C++ – dubnde

+0

@MeThinks, va bene, il mio consiglio è applicabile a C; Ho delineato simulando lo stack unwinding (come il Cleanup Stack di Symbian) come il modo in cui esegui la pulizia delle risorse che hai posto nella tua domanda. – Will

0

Le eccezioni sono di gran lunga un meccanismo generale migliore, ma nei giorni bui e profondi del passato, ho scritto un emulatore di processore che includeva una shell di comandi. La shell usata per impostare jmp/longjmp per la gestione degli interrupt (cioè, il processore è in esecuzione e l'utente colpisce break/ctrl-c, il codice intercetta SIGINT e longjmps nuovamente nella shell).

14

Se siete preoccupati per la pulizia delle risorse, è necessario chiedersi seriamente se longjmp() e setjmp() sono una buona idea.

Se si progetta il proprio sistema di allocazione delle risorse in modo da poter effettuare una pulizia accurata, allora è OK, ma il design tende a essere complicato e in genere incompleto se, in effetti, le librerie standard utilizzate dal codice stesso allocare risorse che devono essere rilasciate. Richiede un'assistenza straordinaria e, poiché non è del tutto affidabile, non è adatto per sistemi a esecuzione prolungata che potrebbero dover sopravvivere a più usi delle chiamate setjmp()/longjmp(), perderanno, si espanderanno e alla fine causeranno i problemi).

+1

+1, perché nessuno sembra invertire le risposte sensate che non rispondono solo ciecamente alla domanda – MatthewD

0

Ho usato setjmp/longjmp ragionevolmente in ordine, per evadere dall'interno di una richiamata, senza dover negoziare la mia strada attraverso vari altri livelli di libreria.

Quel caso (se ricordo correttamente) era dove un codice all'interno di un parser generato da yacc poteva rilevare un problema (non sintattico), e voleva abbandonare l'analisi ma fornire un rapporto di errore ragionevolmente utile al chiamante su l'altro lato di tutto il codice generato da yacc. Un altro esempio era all'interno di un callback chiamato da un parser Expat. In ogni caso, c'erano altri modi per farlo, ma sembravano più ingombranti e oscuri del semplice salvataggio in questo modo.

Come altre risposte hanno rilevato, tuttavia, è necessario fare attenzione al clean-up e molto premuroso per assicurarsi che il codice longjmp sia richiamabile solo nell'ambito della regione protetta dinamicamente dallo setjmp.

Eseguirlo nel contesto della programmazione multi-thread? Sono sicuro che non è impossibile, ma Oooh: tira fuori il tuo pacco di aspirina di famiglia adesso. È probabilmente consigliabile mantenere le coppie setjmp/longjmp il più vicino possibile. Finché una coppia corrispondente a setjmp/longjmp si trova nello stesso thread, mi aspetto che tu stia bene, ma ... stai attento là fuori.

Problemi correlati