Чтение онлайн

ЖАНРЫ

Linux программирование в примерах
Шрифт:

Оператор

break
на уровне
awk
передает
TAG_BREAK
функции
longjmp
, a
continue
уровня
awk
передает
TAG_CONTINUE
. Снова из
eval.c
с некоторыми пропущенными не относящимися к делу подробностями:

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, а может даже какое-нибудь другое значение!

Поделиться с друзьями: