当例外处理时,类型识别如何工作

How type recognision works when exception handling

本文关键字:何工作 工作 识别 类型 处理      更新时间:2023-10-16

c 代码中的某个地方:

try 
{
   foo();
}
catch (const FooExceptionOne& e) 
{
    // ...
}
catch (const FooExceptionTwo& e) 
{
    // ...
}
catch (const std::exception& e) 
{
    // ...
}

FooExceptionOneFooExceptionTwo是从std::exception派生的自定义类。

在抛出例外的时刻;类型识别如何工作?它是某种动态的铸造还是质态,发生在"引擎盖下"?

我的第一个想法是动态的,但是(当然)似乎很慢。

gcc,clang和英特尔C 编译器将类型推入寄存器,可以在此页面上看到:https://godbolt.org/g/g/w0ld0p

代码:

switch (throwType) {
  case 0:
    throw 0;
  case 1:
    throw 0.0;
  case 2:
    throw "test";
}

在GCC中汇编为以下汇编代码:

.L17:
    mov     edi, 4
    call    __cxa_allocate_exception
    xor     edx, edx
    mov     DWORD PTR [rax], 0
    mov     esi, OFFSET FLAT:typeinfo for int
    mov     rdi, rax
    call    __cxa_throw
.L4:
    mov     edi, 8
    call    __cxa_allocate_exception
    xor     edx, edx
    mov     QWORD PTR [rax], OFFSET FLAT:.LC1
    mov     esi, OFFSET FLAT:typeinfo for char const*
    mov     rdi, rax
    call    __cxa_throw
.L3:
    mov     edi, 8
    call    __cxa_allocate_exception
    xor     edx, edx
    mov     QWORD PTR [rax], 0x000000000
    mov     esi, OFFSET FLAT:typeinfo for double
    mov     rdi, rax
    call    __cxa_throw

可以从线条上看到:

mov     esi, OFFSET FLAT:typeinfo for int
mov     esi, OFFSET FLAT:typeinfo for char const*
mov     esi, OFFSET FLAT:typeinfo for double

该类型的TypeInfo位于esi寄存器中存储的GCC中。但是,这是针对编译器的,因此,尽管GCC(以及Clang and Intel)是这种情况,但它可能不适合任何其他编译器(Borland等)。

throw使用的类型信息可以在编译时完全确定,因此这不需要使用C 的RTTI功能,因为它基本上是类型ID的枚举,用于将其映射到相应的捕获块中。

确定如何映射类型的规则,可以在第15.3节中找到有关处理异常的规则。

请查看以下文章C 例外处理内部设备和LLVM中的异常处理。

编译器将生成带有异常的数组/表,typeInfo进行搜索/捕获。