setjmp/longjmp и локальные переменные

Мои вопросы направлены на поведение setjmp/longjmp относительно локальных переменных.

Пример кода:

jmp_buf env;


void abc()
{
  int error;

  ... 
  if(error)
    longjmp(env);
}


void xyz() {
  int v1;           // non-volatile; changed between setjmp and longjmp
  int v2;           // non-volatile; not changed between setjmp and longjmp
  volatile int v3;  // volatile;     changed between setjmp and longjmp
  volatile int v4;  // volatile;     not changed between setjmp and longjmp 

  ...

  if(setjmp(env)) {
    // error handling
    ...
    return;
  }

  v1++; // change v1
  v3++; // change v3

  abc();
}


int main(...) {
  xyz();
}

Документация setjmp/longjmp гласит:

"Все доступные объекты имеют значения на момент вызова longjmp(), за исключением того, что значения объектов с автоматической продолжительностью хранения, локальные для функции, содержащей вызов соответствующего setjmp(), которые не имеют тип volatile-qualified и которые изменяются между вызовом setjmp() и вызовом longjmp(), не определены."

Я вижу следующие две возможные интерпретации:

intepretation1:

Локальные переменные восстанавливаются, кроме тех, которые оба

  • энергонезависимый и
  • изменено

intepretation2:

Локальные переменные восстанавливаются, кроме

  • те, которые являются энергонезависимыми и
  • те, которые изменены

Согласно интерпретации 1 после longjmp, только v1 не определено. v2, v3, v4 определены. Согласно интерпретации2 после longjmp определяется только v4. v1, v2, v3 не определены.

Какой из них прав?

Кстати: мне нужен общий ("переносимый") ответ, который действителен для всех компиляторов, т.е. попытка с одним конкретным компилятором не поможет.

2 ответа

Решение

Интерпретация 1 верна. Если бы толкование 2 было задумано, в исходном тексте использовалось бы "или которые были изменены" вместо "и".

setjmp/longjmp реализуется путем сохранения регистров (включая указатели стека и кода и т. д.) при первой передаче и восстановления их при переходе.

Автоматические (то есть "локальные", размещенные в стеке) переменные, которые не являются "volatile", могут храниться в регистрах, а не в стеке.

В этих условиях longjmp восстановит переменные этих регистров до их значения в тот момент, когда setjmp() был впервые вызван.

Кроме того, особенно умный компилятор может избегать переменных, которые могут быть выведены из состояния другой переменной, и вычислять их по требованию.

Однако, если переменная автоматическая, но ей не присвоен регистр, она может быть изменена кодом между setjmp и longjmp.

Volatile явно указывает компилятору не хранить переменную в регистре.

Поэтому, если вы явно не скажете, что переменная является изменчивой, если вы изменили переменную между setjmp/longjmp, ее значение будет зависеть от выбора, который делает компилятор, и, следовательно, вам не следует полагаться ("неопределенный").

Другие вопросы по тегам