C程序可以处理C ++exception吗?

我正在开发可供C或C ++应用程序使用的C ++组件dll。 暴露的dllfunction如下

#include  #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(); } 

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

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

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

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

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

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

好的,因为它被要求:

C ++示例代码:

 #include  #include  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); } } 

C示例代码:

 #include  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; } 

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

  $ ./xx
 throwingFunc(1)== 0
 throwingFunc(-1)== -2
处理程序调用 - 一定是个例外吗?
中止

因此,虽然你可以从C中捕获exception,但这还不够 – 因为std::terminate()之后的C ++运行时行为是未定义的,并且因为处理程序没有获得任何状态信息(以消除exception类型和/或源)。 处理程序无法清理任何东西。

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

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

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

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