Функция setjmp / longjmp (здесь и далее slj) в C ужасна, и ее поведение может варьироваться в зависимости от реализации. Тем не менее, учитывая отсутствие исключений, slj иногда необходим в C (обратите внимание, что C ++ предоставляет исключения, которые почти во всех отношениях превосходят slj, и что slj плохо взаимодействует со многими функциями C ++).
При использовании slj следует иметь в виду следующее, предполагая, что подпрограмма Parent () вызывает подпрограмму Setter (), которая вызывает setjmp (), а затем вызывает Jumper, который, в свою очередь, вызывает longjmp ().
- Код может по закону выходить из области, в которой выполняется setjmp без выполнения longjmp; однако, как только выходит из области действия, ранее созданный jmp_buf должен рассматриваться как недействительный. Компилятор, вероятно, не будет ничего делать, чтобы пометить его как таковой, но любая попытка использовать его может привести к непредсказуемому поведению, вероятно, включая переход к произвольному адресу.
- Любые локальные переменные в Jumper () будут испаряться при вызове longjmp (), делая их значения неактуальными.
- Всякий раз, когда элемент управления возвращается в Parent, с помощью любых средств, локальные переменные Parent будут такими, какими они были, когда они вызывали Setter, если только у таких переменных не были взяты их адреса и они были изменены с помощью таких указателей; в любом случае, setjmp / longjmp никак не повлияет на их значения. Если у таких переменных не взяты их адреса, возможно, что setjmp () может кэшировать значения таких переменных, а longjmp () может их восстановить. В этом случае, однако, переменные не смогут изменить время между кэшированием и восстановлением, поэтому кэш / восстановление не окажет видимого эффекта.
- Переменные в Setter могут кэшироваться или не кэшироваться с помощью вызова setjmp (). После вызова longjmp () такие переменные могут иметь значение, которое они имели при выполнении setjmp (), или значения, которые они имели, когда он вызывал подпрограмму, которая в конечном итоге вызывала longjmp (), или любую их комбинацию. По крайней мере, на некоторых диалектах C такие переменные могут быть объявлены как «volatile», чтобы предотвратить их кэширование.
Хотя setjmp / longjmp () иногда может быть полезен, он также может быть очень опасным. В большинстве случаев нет ошибочного кода защиты, вызывающего неопределенное поведение, и во многих реальных сценариях неправильное использование может привести к возникновению плохих вещей (в отличие от некоторых видов неопределенного поведения, где фактический результат часто может совпадать с тем, что программист предназначен).