675 longjmp(loop_tag, TAG_BREAK);
676 break;
677
678 case Node_K_continue:
679 INCREMENT(tree->exec_count);
/* ... */
696 longjmp(loop_tag, TAG_CONTINUE);
670 break;
Вы можете думать о setjmp()
как об установке метки, а о longjmp()
как выполнении goto
с дополнительным преимуществом возможности сказать, откуда «пришел» код (по возвращаемому значению).
12.5.2. Обработка масок сигналов: sigsetjmp()
и siglongjmp()
По историческим причинам, которые, скорее всего, утомили бы вас до слез, стандарт С 1999 г. ничего не говорит о влиянии setjmp()
и longjmp()
на состояние сигналов процесса, а POSIX явно констатирует, что их влияние на маску сигналов процесса (см. раздел 10.6 «Сигналы POSIX») не определено.
Другими словами, если программа изменяет свою маску сигналов процесса между первым вызовом setjmp()
и вызовом longjmp()
, каково состояние маски сигналов процесса после longjmp()
? Та ли эта маска, когда была впервые вызвана setjmp()
? Или это текущая маска? POSIX явно утверждает, что «нет способа это узнать».
Чтобы сделать обработку маски сигналов процесса явной, POSIX ввел две дополнительные функции и один typedef
:
#include
int sigsetjmp(sigjmp_buf env, int savesigs); /* Обратите внимание:
sigjmp_buf, не jmp_buf! */
void siglongjmp(sigjmp_buf env, int val);
Главным отличием является аргумент savesigs
функции sigsetjmp()
. Если он не равен нулю, текущий набор заблокированных сигналов сохраняется в env
вместе с остальным окружением, которое сохраняется функцией setjmp()
. siglongjmp()
с env
, в которой savesigs
содержала true, восстанавливает сохраненную маску сигналов процесса
ЗАМЕЧАНИЕ. POSIX также ясен в том, что если savesigs
равен нулю (false), сохраняется ли маска сигналов процесса или восстанавливается, не определено, как в случае с setjmp()
/longjmp()
. Это, в свою очередь, предполагает, что если собираетесь использовать 'sigsetjmp(env, 0)
', вы также можете не беспокоиться: все дело в том, чтобы иметь контроль над сохранением и восстановлением маски сигналов процесса!
12.5.3. Важные предостережения
Есть несколько технических предостережений, о которых нужно знать.
Во-первых, поскольку сохранение и восстановление среды может быть беспорядочной машинно-зависимой задачей, setjmp()
и longjmp()
могут быть макросами
Во-вторых, стандарт С ограничивает использование setjmp()
следующими ситуациями.
• В качестве единственного контролирующего выражения в операторе цикла или условном операторе (if
, switch
).
• В качестве одного операнда выражения сравнения (==
, <
и т.д.), с целой константой в качестве другого операнда. Выражение сравнения может быть единственный контролирующим выражением цикла или условного оператора.
• В качестве операнда унарного оператора '!
', причем результирующее выражение является единственным контролирующим выражением цикла или условного оператора.
• В качестве всего выражения оператора-выражения, возможно, приведенного к типу void
. Например:
(void)setjmp(buf);
В-третьих, если вы хотите изменить локальную переменную в функции, которая вызывает setjmp()
, longjmp()
значение, нужно объявить эту переменную как volatile
. В противном случае все локальные переменные, не являющиеся volatile
и изменившиеся после того, как была первоначально вызвана setjmp()
, имеют неопределенные значения. (Обратите внимание, что сама переменная jmp_buf
не должна объявляться как volatile
.) Например:
1 /* ch12-setjmp.с --- демонстрирует setjmp()/longjmp() и volatile. */
2
3 #include
4 #include
5
6 jmp_buf env;
7
8 /* comeback --- выполнение longjmp */
9
10 void comeback(void)
11 {
12 longjmp(env, 1);
13 printf("This line is never printed\n");
14 }
15