с некоторыми пропущенными не относящимися к делу подробностями:
657 case Node_K_break:
658 INCREMENT(tree->exec_count);
/* ... */
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 <setjmp.h> /* POSIX */
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 <stdio.h>
4 #include <setjmp.h>
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
16 /* main - вызов setjmp, действия с переменными, вывод значений */
17
18 int main(void)
19 {
20 int i = 5;
21 volatile int j = 6;
22
23 if (setjmp(env) == 0) { /* первый раз */
24 i++;
25 j++;
26 printf("first time: i = %d, j = %d\n", i, j);
27 comeback));
28 } else /* второй раз */
29 printf("second time: i = %d, j = %d\n", i, j);
30
31 return 0;
32 }
В этом примере сохранение своего значения ко второму вызову
printf
гарантируется
лишь
j (строка 21). Значение (строка 20) в соответствии со стандартом С 1999 г. не определено. Это может быть 6, может быть 5, а может даже какое-нибудь другое значение!