#c #language-lawyer #setjmp
#c #язык-юрист #setjmp
Вопрос:
В моем понимании типичным использованием setjmp()
и longjmp()
является обработка исключений (использование в libpng
должно быть известным примером этого), и для одного вызова будет не более одного longjmp()
вызова setjmp()
.
Безопасно ли выполнять longjmp()
несколько раз для одного setjmp()
такого вызова?
#include <stdio.h>
#include <setjmp.h>
jmp_buf jb;
int i;
int main(void) {
i = 0;
setjmp(jb);
printf("%dn", i);
i ;
if (i < 10) longjmp(jb, 1);
return 0;
}
0
1
2
3
4
5
6
7
8
9
Я успешно получил ожидаемый результат от этого выполнения, но гарантировано ли это?
Или будет jmp_buf
признан недействительным longjmp()
, когда будет использован для этого один раз?
setcontext — Википедия говорит: «Их можно рассматривать как расширенную версию setjmp / longjmp; тогда как последний допускает только один нелокальный переход вверх по стеку», но я не нашел описаний, запрещающих многократное использование longjmp()
подобных N1570 7.13 нелокальных переходов <setjmp.h> .
Я знаю, что использование setjmp()
and longjmp()
не рекомендуется, но мне интересно, можно ли их использовать в качестве обходного пути при использовании операторов цикла ( for
, while
, do-while
), а goto
операторы запрещены, но использование setjmp()
and longjmp()
не запрещено в некоторых тестах по программированию. (использование рекурсии может быть ответом на этот тип вопросов, но при попытке работать с большими данными, требующими много итераций, возникает риск переполнения стека)
Комментарии:
1. Это разрешено до тех пор, пока контекст, который устанавливает буфер перехода (вызывается
setjmp()
), не был завершен, поэтому сохраненные значения все еще действительны.2. В пункте 2 раздела 7.13.2.1 перечислены случаи, когда
longjmp(env)
значение не определено. Повторное использование одной и той же среды не упоминается.3. @Barmar — Не уверен, что это о многом говорит. Стандарт допускает, что вещи могут быть неопределенными из-за пропусков.
4. @StoryTeller-UnslanderMonica Верно, но эта философия может сделать почти все неопределенным. Явно ли указано, что вы можете читать переменную несколько раз?
5. @NateEldredge: Предположительно, можно было бы организовать
setjmp()
повторный вызов; не похоже, что ваше использование стало бы невозможным, если бы контекст перехода можно было использовать только один раз, хотя его определенно проще использовать повторно.
Ответ №1:
Безопасно ли выполнять longjmp() несколько раз для одного вызова setjmp () подобным образом?
Можно создать строго соответствующую программу, которая вызывает longjmp()
несколько раз, чтобы вернуться к точке одного и того же setjmp()
вызова. Это зависит от состояния абстрактной машины, включая содержимое памяти, и особенно от состояния jmp_buf
, в котором setjmp()
вызов записывает состояние, необходимое для возврата к точке этого вызова. Стандарт определяет, что
Все доступные объекты имеют значения, а все остальные компоненты абстрактной машины имеют состояние на момент
longjmp
вызова функции, за исключением [… деталей, которых можно избежать или сделать несущественными …] .
(C2018 7.13.2.1 / 3)
В частности, это означает, что longjmp()
вызов не должен изменять значение jmp_buf
, из которого он получает свою информацию, и не может быть никакого скрытого состояния в другом месте, которое longjmp()
могло бы обновиться, чтобы пометить соответствующее setjmp()
как израсходованное. Если состояние машины разрешает соответствующий longjmp()
вызов, то эквивалентный longjmp()
вызов все равно должен соответствовать после результирующего второго (или третьего и т.д.) Возврата из соответствующего setjmp()
вызова.
Комментарии:
1. Обратите внимание, что это не тот случай, если jmp_buf является автоматическим локальным для области setjmp — в этом случае […подробности], которые вы исключили, вступают в игру, и его значение становится неопределенным
2. Обратите внимание, что если
i
была определена как локальная автоматическая переменная, ее значение послеlongjmp()
может или не может быть сохранено,setjmp()
поэтому поведение будет неопределенным.3. @ChrisDodd Стандарт гласит, что значение объекта становится неопределенным, если оно было изменено между
setjmp
longjmp
вызовами и .jmp_buf
Изменяется между ними?4. @LanguageLawyer: можно было бы предположить, что сам setjmp изменит jmp_buf после вызова. Но я согласен, что, похоже, нет никаких причин для того, чтобы это вызывало какие-либо проблемы.
5. @ChrisDodd можно было бы предположить, что сам setjmp изменит jmp_buf после вызова , может быть, вы имеете в виду при вызове, а не после ?