g++编译器具有零成本异常处理的特点。据我了解,try
什么都不做,但是当抛出异常时,会执行异常处理程序的子例程。像这样:
void foo() {
try {
bar(); // throws.
} catch (Type exc) {
baz();
}
}
在伪代码(c-stylish)中看起来像这样:
void foo() {
bar();
return;
catch1_Type:
baz();
}
bar() 抛出。异常例程执行以下操作:
啊,返回地址在函数 foo() 中!并且返回地址在第一个 try-catch 块中,我们抛出类型 Type,所以异常处理程序的地址是 foo+catch1_Type。所以清理堆栈,这样我们就到了那里!
现在我的问题是:有没有办法在 C 中实现它?(可以是 C99 或更新版本,虽然我对 gcc 支持的 C 方言感兴趣)。我知道我可以使用例如 libunwind 进行堆栈检查和遍历,尽管我不知道如何获取catch1_Type
标签的地址。这可能是不可能的。
异常处理程序可能是一个不同的函数,这同样可以,但是如何foo
在另一个函数中获取堆栈帧的局部变量的地址?这似乎也是不可能的。
那么……有什么办法吗?我不想用这个进入汇编程序,但如果其他一切都失败了也是可以接受的(尽管局部变量 - 伙计,如果使用不同的优化级别,你永远不知道它们在哪里)。
并且要明确 - 这个问题的目的是避免setjmp/longjmp 方法。
编辑:我发现了一个很酷的想法,但并不完全有效:
gcc 中的嵌套函数。他们能做什么?
- 可以访问局部变量,
- 有可能在父函数中转到本地标签!
- 可以被我们函数的被调用者调用,前提是我们传递一个指向嵌套函数的指针,因此它可以通过被调用者中的指针获得。
不利的一面是阻止我做任何零成本的事情:
- 如果它们未使用,它们即使在 -O0 级别也会被优化。我能对此做些什么吗?如果可以的话,我可以在抛出异常时通过符号名称获取地址,它只会完成实现异常的工作,而这些异常在不抛出时不会花费任何成本......