Подтвердить что ты не робот

Каковы "хорошие" способы использования longjmp/setjmp для обработки ошибок C?

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

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

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

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

4b9b3361

Ответ 2

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

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

Ответ 3

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

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

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

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

Ответ 4

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

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

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

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

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

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

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

Ответ 5

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

Ответ 6

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

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

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

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