g++ имеет функцию обработки исключений с нулевой стоимостью. Насколько я понимаю, try
ничего не делает, но когда генерируется исключение, выполняется подпрограмма для обработчика исключений. Вот так:
void foo() {
try {
bar(); // throws.
} catch (Type exc) {
baz();
}
}
В псевдокоде (c-стильный) будет выглядеть так:
void foo() {
bar();
return;
catch1_Type:
baz();
}
bar() выбрасывает. Процедура исключения выполняет следующие действия:
Ah, обратный адрес находится в функции foo()! И обратный адрес находится в первом блоке try-catch, и мы бросаем тип Type, поэтому процедура обработчика исключений находится по адресу foo + catch1_Type. Поэтому очистите стек, чтобы мы оказались там!
Теперь мой вопрос: есть ли способ реализовать его в C? (Может быть C99 или новее, хотя меня интересует диалект C, поддерживаемый gcc). Я знаю, что я могу использовать, например, libunwind для проверки стека и обхода, хотя я понятия не имею, как получить адрес метки catch1_Type
. Это может быть невозможно.
Обработчик исключений может быть другой функцией, одинаково хорошо, но тогда как получить адреса локальных переменных stackframe foo
в этой другой функции? Это также кажется невозможным.
Итак... есть ли способ сделать это? Я бы не хотел входить в ассемблер с этим, но это также приемлемо, если все остальное не удается (хотя локальные переменные - человек, вы никогда не знаете, где они находятся, используя разные уровни оптимизации).
И чтобы быть понятным - цель этого вопроса - избежать подхода setjmp/longjmp.
EDIT: я нашел довольно крутую идею, но не работает полностью:
Вложенные функции в gcc. Что они могут сделать?
- имеют доступ к локальным переменным,
- есть возможность получить локальные метки в родительской функции!
- может быть вызван вызовами нашей функции при условии, что мы передаем указатель на вложенную функцию, поэтому она доступна указателем в вызываемом абоненте.
Даунсайд, который мешает мне делать что-то нулевое:
- они оптимизированы даже на уровне -O0, если они не используются. Могу я что-нибудь сделать? Если бы я мог, я мог бы получить адрес по имени символа, когда будет выбрано исключение, и он просто выполнит выполнение исключений, которые стоили бы nohing, когда они не были выбраны...