C程序可以处理C++异常吗?

Ahm*_*aid 16 c c++ exception-handling

我正在开发可供C或C++应用程序使用的C++组件DLL.暴露的dll功能如下

#include <tchar.h>
#ifdef IMPORT
#define DLL __declspec(dllimport)
#else 
#define DLL __declspec(dllexport)
#endif

extern "C" {

    DLL  bool __cdecl Init();
    DLL  bool __cdecl Foo(const TCHAR*);
    DLL  bool __cdecl Release();

}
Run Code Online (Sandbox Code Playgroud)

这些函数的内部实现是没有公开的C++类,我假设使用这种风格,dll可以在C或C++应用程序中使用.问题是我没有处理任何类型的c ++异常(即bad_alloc),我将这些东西留给了调用者(更高层).经过与同事的多次辩论,我应该捕获所有异常并返回错误代码或至少是错误的,因为在C应用程序的情况下,它无法处理C++异常?真的吗?我一般应该做些什么?如果您正在开发将由其他系统使用的组件,是否有处理exeptions的经验法则.

vit*_*aut 18

C没有异常,因此通常您应该捕获所有异常并返回错误代码和/或提供返回有关上一个错误的信息的函数.


Rup*_*Rup 18

如果这是使用MSVC的Windows,那么是的,您可以捕获C中的异常,但是您无法很好地捕获它们.C++异常通过OS ABI的结构化异常处理机制提供,Microsoft具有__try,__ except,__finally C扩展来处理OS结构化异常.请注意,这些包括您通常希望终止程序并记录错误报告的访问冲突,被零除等.您可以通过代码0xE04D5343(4D 53 43 ="MSC")识别C++异常,然后将其余部分打开.

总而言之,您可能不希望在DLL边界上抛出异常,当然,如果您只暴露C API,则肯定不会.


Cad*_*nge 13

作为一般规则,您绝不应允许C++异常传播到模块的边界之外.这是因为C++标准没有规定必须如何实现异常传播,因此这是编译器(和编译器标志)和操作系统相关的.您不能保证调用模块的代码将使用与模块相同的编译器标志的相同编译器进行编译.事实上,正如您在使用此问题进行演示时,您无法保证调用模块的代码将使用相同的语言编写.

有关详细信息,请参阅Sutter和Alexandrescu在C++编码标准中的第62项.


Fra*_*kH. 9

好的,因为它被要求:

C++示例代码:

#include <typeinfo>
#include <exception>
extern "C" {
void sethandler(void (*func)(void)) { std::set_terminate(func); }
int throwingFunc(int arg) {
    if (arg == 0)
        throw std::bad_cast();
    return (arg - 1);
}
}
Run Code Online (Sandbox Code Playgroud)

C示例代码:

#include <stdio.h>

extern int throwingFunc(int arg);
extern void sethandler(void (*func)(void));

void myhandler(void)
{
    printf("handler called - must've been some exception ?!\n");
}

int main(int argc, char **argv)
{
    sethandler(myhandler);

    printf("throwingFunc(1) == %d\n", throwingFunc(1));
    printf("throwingFunc(-1) == %d\n", throwingFunc(-1));
    printf("throwingFunc(0) == %d\n", throwingFunc(0));
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

当我编译这两个,将它们链接在一起并运行它(Ubuntu 10.04,gcc 4.4.5,x64),我得到:

$ ./xx
throwingFunc(1) == 0
throwingFunc(-1) == -2
handler called - must've been some exception ?!
Aborted

因此,虽然您可以从C中捕获异常,但这几乎不够 - 因为之后的C++运行时行为std::terminate()未定义,并且因为处理程序没有获得任何状态信息(以消除异常类型和/或源).处理程序无法清理任何内容.

顺便说一下,我std::bad_cast()在这个例子中故意选择了异常类型.这是因为抛出说明了std::set_unexpected()和之间行为的差异std::set_terminate()- 意外处理程序将被调用所有非std::bad_*异常,而为了捕获标准异常,需要终止处理程序......看到困境?线束太宽而无法实际使用:(


sha*_*oth 7

如果调用者被设计为处理它们,则仅将异常传播给调用者.我想在你的情况下,terminate()一旦任何异常逃脱C++代码,将立即调用,因为从C++运行时开始,该异常尚未处理.

COM服务器设计也出现了同样的情况 - 客户端可以使用任何语言/技术.rul是没有异常应该逃避COM服务器方法 - 必须在HRESULT和(可选)IErrorInfo中捕获和转换所有异常.你应该在你的情况下做同样的事情.

如果C代码夹在两层C++代码之间传播C代码异常仍然是一个非常糟糕的主意.