Подтвердить что ты не робот

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(), которые не имеют изменчивого типа и которые изменены между вызовом setjmp() и longjmp() являются неопределенными. "

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

intepretation1:

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

  • нелетучий и
  • изменен

intepretation2:

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

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

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

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

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

4b9b3361

Ответ 1

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

Ответ 2

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

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

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

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

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

Volatile явно сообщает компилятору, чтобы он не хранил переменную в регистре.

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