[<<Previous Entry] [^^Up^^] [Next Entry>>] [Menu] [About The Guide]
 Нелокальный goto

Библиотечная функция  longjmp(3C) представляет  собой аналог оператора
goto для  перехода между  функциями. Управление  может  быть  передано
только в точку, которая была помечена вызовом setjmp(3).

setjmp(3),  который   метит  точку  для  передачи  управления,  должен
получить в  качестве параметра буфер для сохранения текущего контекста
функции в данной точке. longjmp(3) вызывается с тем же самым буфером в
качестве параметра.  Исполнение возобновится  с  положения  последнего
setjmp(3) для  этого буфера.  Значение val  будет возвращено setjmp(3)
после выполнения longjmp(3), и должно быть ненулевым.

Тип jmp_buf представляет собой массив целых чисел, описанный с помощью
конструкции  typedef.  Число  элементов  в  этом  массиве  -  машинно-
зависимо.

Функция  longjmp(3)  возвращает  управление  к  последнему  setjmp(3),
который  заполнил   буфер  env,  используемый  как  аргумент  longjmp.
Различие между  прямым вызовом  setjmp(3) и  возвратом  к  нему  через
longjmp(3)  состоит   в  том,   что   возвращаемое   значение   будет,
соответственно, нулевым  и ненулевым.  Если longjmp(3)  получит ноль в
качестве val, значение, выданное setjmp(3), будет 1.

Справки: /usr/include/setjmp.h
                           НЕЛОКАЛЬНЫЙ goto


setjmp(3C)

ИМЯ

     setjmp, longjmp - нелокальный goto



ИСПОЛЬЗОВАНИЕ

     #include <setjmp.h>

     int setjmp (jmp_buf env);
     void longjmp (jmp_buf env, int val);



ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

     setjmp(3) возвращает 0, когда встречается в выполняемой
     последовательности кодов

     setjmp(3) возвращает ненулевое значение, если вызов longjmp(3)
     привел к переходу к месту вызова setjmp(3)
                  setjmp(3C) и longjmp(3C) - Пример

Эта  программа   демонстрирует,  каким   образом  часто   используются
setjmp(3C) и longjmp(3C). Эта программа представляет собой циклическое
меню внутри  функции main.  Вызов setjmp(3C)  используется  для  того,
чтобы пометить точку в программе непосредственно перед циклом.
Замечание: К примеру, ed(1) и ex(1) делают в точности то же самое, так
что если  во время  исполнения 1,$p  будет  нажата  клавиша  <DELETE>,
редактор не  возобновляет печать  после обработки  SIGINT, а выполняет
longjmp к месту приема очередной команды.

Меню в примере содержит следующие команды:
  s             печатать квадраты целых чисел
  t             печатать дату и время
  q             выйти из программы

Для каждой  буквы-команды вызывается определенная функция, выполняющая
требуемую операцию.  Если пользователь  нажимает  <DELETE>,  программа
продолжается с  точки, помеченной  setjmp, так  как функция  обработки
сигнала вызывает  longjmp(3), вместо  возврата к месту, где находилось
управление до перехвата сигнала.

2-3       Включить <setjmp.h>  и объявить  переменную env типа jmp_buf
          (typedef для массива целых чисел).
8         Сигналы прерывания  будут перехватываться  и  обрабатываться
          заданной пользователем функцией ljmain.
9         Текущая точка  программы  помечена  setjmp(3).  Возвращаемое
          значение будет нулевым. Оно станет ненулевым при последующих
          переходах на эту точку при вызове longjmp.

12        Вход в цикл меню.

15-26     Меню вызывает функции, выполняющие требуемые команды.

28-33     Функция обработки сигнала SIGINT переустанавливает сигнал на
          ту же  функцию (т.е.  на  себя),  печатает  "INTERRUPTED"  и
          выполняет longjmp обратно в функцию main.
...       Не  показаны   sfn(),  которая  печатает  последовательность
          квадратов, и tfn(), печатающая дату и время.

Возможно несколько  вызовов setjmp(3), позволяющие делать longjmp(3) в
различные  точки.  Однако,  каждый  вызов  требует  своей  собственной
переменной jmp_buf.

Этот пример демонстрируется следующим образом:
$ setjmp
cmd: s
0    14916253649
64   81100121144169225
<DELETE>
INTERRUPTED
Before loop
cmd: q
$

Файл: setjmp.c
                  setjmp(3C) И longjmp(3C) - ПРИМЕР


 1      #include <signal.h>
 2      #include <setjmp.h>
 3      jmp_buf env1;
 4      void ljmain(int);
 5
 6      main() {
 7            int retcode;
 8            signal(SIGINT, ljmain);
 9            retcode = setjmp(env1);
10            if (retcode != 0) printf("\nBefore loop\n");
11
12            while( 1 ) menu();
13      }
14
15      menu() {
16             char resp[2];
17      prompt: printf("cmd: ");
18             scanf("%s",resp);
19             switch(resp[0]){
20                     case 's': sfn(); break;
21                     case 't': tfn(); break;
22                     case 'q': exit(0);
23                     default:  printf("?\n");
24                               goto prompt;
25             }
26      }
27
28      void ljmain(int sig)
29      {
30             signal(SIGINT, ljmain);
31             printf("\nINTERRUPTED\n");
32             longjmp(env1, 1);
33      }
34
...