将C ++接口中的longjmps隐藏到C代码中

时间:2013-12-19 16:00:55

标签: c++ c api longjmp

为旧C代码生成C ++ API的正确方法是什么?该代码广泛使用带有多个跳转目标的longjmp进行错误管理?

我的想法是编写一个函数来为每个使用过的目标设置跳转目标,例如:

void catchJumps() {
    if (setjmp(target1)) throw Error1(); //Error1 and Error2 are some exception classes
    if (setjmp(target2)) throw Error2();
    //...
}

然后我在每个使用C代码的C ++函数(在每个范围内,更具体)中调用catchJumps

int some_wrapper() {
    catchJumps();
    callCFunction()

    for (int i = 0; i < 1000; i++) {
        catchJumps();
        callOtherCFunction();
    }

    catchJumps();
    callOneMoreCFunction();
    callEvenOneMoreCFunction();
}

这是一种在不破坏堆栈的情况下捕获所有longjump的安全方法吗?我知道,longjmp进入不同的堆栈框架是危险的。现在,我的函数catchJumps位于另一个堆栈帧中而不是调用some_wrapper。我希望(或者我甚至可以做到)catchJumps可以内联,所以框架是相同的,但我不知道。

调用范围对象的所有析构函数时,每个范围(以及上面的循环之后)的调用都是必要的,对吗?

如果这不是将longjmps“转换”为调用应用程序断言的有效方法,我们还能做些什么呢?

2 个答案:

答案 0 :(得分:3)

使用catchJumps自动对象具有析构函数时可能会遇到问题,如https://stackoverflow.com/a/1376099/471164中所述并引用18.7 / 4“其他运行时支持”:

  

如果抛出的异常会破坏任何自动对象   将控制转移到程序中的另一个(目标)点,   然后在转移的投掷点调用longjmp(jbuf,val)   对同一(目标)点的控制具有未定义的行为。

我认为更好的方法是为您使用的每个C函数创建一个包装器,并且可以longjmp将所有这些非本地的getos转换为异常。这也将使您的代码更清晰,因为您不会在所有地方都有catchJumps(),而只是在这些包装函数中。

答案 1 :(得分:2)

由于您在库中遇到了这样的API,让catchJumps通过要求传入零参数可调用并使用函数指针或boost/std::function来执行实际调用?

template <typename CallMe>
void catchJumps(CallMe wrappee)
{
    if (setjmp(target1)) throw Error1(); //Error1 and Error2 are some exception classes
    if (setjmp(target2)) throw Error2();
    //...

    wrappee();
}

int some_wrapper()
{
    catchJumps(&callCFunction);

    for (int i = 0; i < 1000; i++)
    {
        catchJumps(&callOtherCFunction);
    }

    catchJumps(&callOneMoreCFunction);
    catchJumps(&callEvenOneMoreCFunction);
}