Quali sono alcuni modi "buoni" per utilizzare longjmp / setjmp per la gestione degli errori C?

StackOverflow https://stackoverflow.com/questions/819864

Domanda

Devo usare C per un progetto e sto pensando di usare longjmp / setjmp per la gestione degli errori in quanto penso che sarà molto più facile gestire gli errori in un posto centrale rispetto ai codici di ritorno. Gradirei se ci fossero dei suggerimenti su come farlo.

Sono particolarmente preoccupato che la pulizia delle risorse venga eseguita correttamente se si verifica un errore del genere.

Inoltre, come posso gestire gli errori che portano a programmi multi-thread che li utilizzano?

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

È stato utile?

Soluzione

Dai un'occhiata a questo esempio / tutorial:
http://www.di.unipi.it/~nids/docs/longjump_try_trow_catch .html

Altri suggerimenti

Se sei preoccupato per la pulizia delle risorse, devi chiederti seriamente se longjmp () e setjmp () sono una buona idea.

Se si progetta il proprio sistema di allocazione delle risorse in modo da poter effettivamente ripulire accuratamente, allora va bene - ma quel design tende ad essere complicato, e in genere incompleto se, in effetti, le librerie standard utilizzate dal proprio codice allocano risorse che devono essere rilasciate. Richiede cure straordinarie e, poiché non è del tutto affidabile, non è adatto a sistemi di lunga durata che potrebbero dover sopravvivere a molteplici usi delle chiamate setjmp () / longjmp () (coleranno, si espanderanno e alla fine causeranno problemi).

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

Symbian ha uno 'stack di pulizia' globale che spingi e fai scoppiare le cose che vuoi che vengano ripulite in caso di un salto. Questa è l'alternativa manuale allo stack automatico che svolge un compilatore C ++ quando viene generata un'eccezione C ++.

Symbian aveva "trappole" a cui sarebbe saltato fuori; questi potrebbero essere nidificati.

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

Tutti insieme, penso che le giuste eccezioni C ++ siano meno inclini a errori di codifica e molto più veloci rispetto al rotolamento del proprio equivalente C.

(I compilatori C ++ moderni sono molto bravi con le eccezioni 'zero overhead' quando non vengono lanciati, ad esempio; longjmp () deve memorizzare lo stato di tutti i registri e così anche quando il salto non verrà successivamente adottato, quindi fondamentalmente non potrà mai essere veloce come le eccezioni.)

L'uso di C ++ come C migliore, in cui si adottano solo eccezioni e RAII, sarebbe una buona strada se si dovesse usare longjmp () perché l'emulazione delle eccezioni sia allettante per te.

Ho sempre trovato un uso per setjmp () / longjmp () e non aveva a che fare con la gestione degli errori.

Non c'è davvero bisogno di usarlo per quello poiché può sempre essere refactored 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 codici cattivi più facili delle alternative.

FWIW, l'unico posto in cui sono stati preziosi è stato un progetto che ho realizzato nei primi giorni del settore (MS-DOS 6 time frame). Sono riuscito a mettere insieme una libreria multi-threading cooperativa usando Turbo C che ha usato quelle funzioni in una funzione yield () per cambiare attività.

Sono abbastanza sicuro di non averli toccati (o di averne avuto bisogno) da quei giorni.

Le eccezioni sono di gran lunga un meccanismo generale migliore, ma nei giorni bui e profondi del passato C, ho scritto un emulatore di processore che includeva una shell dei comandi. La shell utilizzata per impostarejmp / longjmp per la gestione degli interrupt (ovvero, il processore è in esecuzione e l'utente preme break / ctrl-c, il codice intercetta SIGINT e longjmps di nuovo sulla shell).

Ho usato setjmp / longjmp ragionevolmente in ordine, per sfuggire a un callback, senza dover passare attraverso vari altri livelli di libreria.

Quel caso (se ricordo bene) era quello in cui un codice all'interno di un parser generato da Yacc poteva rilevare un problema (non sintattico) e voleva abbandonare l'analisi ma restituire un messaggio di errore ragionevolmente utile al chiamante sul 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 rispetto al semplice salvataggio in questo modo.

Come hanno sottolineato altre risposte, tuttavia, è necessario essere attenti alla pulizia e molto attenti a assicurarsi che il codice longjmp sia richiamabile solo nell'ambito della regione protetta dinamicamente dal setjmp .

Farlo nel contesto della programmazione multi-thread? Sono sicuro che non è impossibile, ma Oooh: esci subito dal tuo pacchetto famigliare di aspirina. Probabilmente è saggio tenere le coppie setjmp / longjmp il più vicino possibile. Finché una coppia setjmp / longjmp corrispondente si trova nello stesso thread, mi aspetto che tu stia bene, ma ... stai attento là fuori

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top