Что является хорошим & # 8220; способы использовать longjmp / setjmp для обработки ошибок C?

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

Вопрос

Мне нужно использовать C для одного проекта, и я думаю об использовании longjmp / setjmp для обработки ошибок, так как я думаю, что обрабатывать ошибки в одном центральном месте будет намного проще, чем кодам возврата. Буду признателен, если есть какие-то советы о том, как это сделать.

Я особенно обеспокоен тем, как правильно выполняется очистка ресурса в случае возникновения такой ошибки.

Кроме того, как мне обрабатывать ошибки, которые приводят к их использованию многопоточными программами?

Еще лучше, есть ли библиотека C, которая уже существует для обработки ошибок / исключений?

Это было полезно?

Решение

Посмотрите на этот пример / учебник:
http://www.di.unipi.it/~nids/docs/longjump_try_trow_catch .html

Другие советы

Если вы беспокоитесь об очистке ресурса, вам следует серьезно задуматься, являются ли longjmp () и setjmp () хорошей идеей.

Если вы спроектируете свою систему распределения ресурсов так, чтобы вы могли на самом деле точно очистить ее, тогда все в порядке - но такая разработка, как правило, сложная и, как правило, неполная, если на самом деле стандартные библиотеки, используемые вашим кодом, сами выделяют ресурсы, которые должны быть освобождены. Это требует особой осторожности, и, поскольку оно не совсем надежно, оно не подходит для долго работающих систем, которым может понадобиться выдержать многократное использование вызовов setjmp () / longjmp () (они будут утекать, расширяться и в конечном итоге приводить к проблемы).

В Symbian реализован механизм Leave в терминах longjmp () , и это служит хорошим обзором всего, что вам нужно сделать.

В Symbian есть глобальный «стек очистки», в который вы нажимаете и извлекаете вещи, которые хотите очистить, в случае скачка. Это ручная альтернатива автоматическому разматыванию стека, которое делает компилятор C ++ при возникновении исключения C ++.

У Symbian были «жгуты ловушек», на которые он мог бы выпрыгнуть; они могут быть вложенными.

(Symbian недавно переопределил его с точки зрения исключений C ++, но интерфейс остался неизменным).

Все вместе, я думаю, что правильные исключения C ++ менее подвержены ошибкам кодирования и намного быстрее, чем переход на собственный эквивалент C.

(например, современные компиляторы C ++ отлично справляются с исключениями «ноль накладных расходов», когда они не генерируются; longjmp () должен хранить состояние всех регистров и тому подобное, даже когда происходит переход позже не берется, поэтому в принципе никогда не может быть так быстро, как исключения.)

Использование C ++ в качестве лучшего C, когда вы принимаете только исключения и RAII, было бы хорошим способом, если использование longjmp () для эмуляции исключений может быть заманчивым.

Я только когда-либо нашел одно использование для setjmp () / longjmp () , и это не было связано с обработкой ошибок.

Нет необходимости использовать его для этого, так как он всегда может быть преобразован во что-то более простое. Использование setjmp () / longjmp () очень похоже на goto тем, что им легко злоупотреблять. Все, что делает ваш код менее читабельным, в целом является плохой идеей. Обратите внимание, что я не говорю, что они изначально плохие, просто они могут привести к плохому коду проще, чем альтернативы.

FWIW, единственное место, где они были бесценны, был проект, который я делал в первые дни индустрии (временные рамки MS-DOS 6). Мне удалось собрать совместную многопоточную библиотеку с использованием Turbo C, которая использовала эти функции в функции yield () для переключения задач.

Я почти уверен, что с тех пор я их не трогал (или не нуждался).

Исключения - гораздо лучший общий механизм, но в глубокие мрачные времена прошлого C я написал эмулятор процессора, который включал командную оболочку. Оболочка, используемая для setjmp / longjmp для обработки прерываний (т. Е. Процессор работает, и пользователь нажимает break / ctrl-c, код перехватывает SIGINT и longjmps обратно в оболочку).

Я достаточно аккуратно использовал setjmp / longjmp , чтобы убежать из обратного вызова без необходимости согласовывать свой путь через различные другие уровни библиотеки.

В этом случае (если я правильно помню) был случай, когда код в синтаксическом анализаторе, сгенерированном yacc, мог обнаружить (не синтаксическую) проблему и хотел отказаться от синтаксического анализа, но дать вызывающему пользователю достаточно полезный отчет об ошибке на другая сторона всего кода, сгенерированного YACC. Другой пример был внутри обратного вызова, вызванного из синтаксического анализатора Expat. В каждом случае были другие способы сделать это, но они казались более громоздкими и неясными, чем просто выручка таким образом.

Как уже отмечалось в других ответах, необходимо соблюдать осторожность при очистке и тщательно продумать, чтобы код longjmp мог вызываться только в пределах области, динамически защищенной. setjmp .

Делаете ли вы это в контексте многопоточного программирования? Я уверен, что это не невозможно, но Ооо: достань свою семейную пачку аспирина сейчас. Вероятно, целесообразно держать пары setjmp / longjmp как можно ближе друг к другу. Пока соответствующая пара setjmp / longjmp находится в одном потоке, я ожидаю, что вы будете в порядке, но ... будьте осторожны.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top