5

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

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

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

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

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

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

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

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

每个作用域中的调用(以及上面的循环之后)应该是调用作用域对象的所有析构函数所必需的,对吧?

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

4

2 回答 2

3

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

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

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

于 2013-12-19T16:19:49.093 回答
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);
}
于 2013-12-19T16:20:03.100 回答