这些函数的内部实现是不暴露的C++类,我假设使用这种样式,DLL可以在C或C++应用程序中使用。 问题是,我不处理任何类型的C++异常(即BADYOLL),而我把这些东西留给了调用方(更高层)。 经过与同事的激烈辩论,我应该捕捉所有异常并返回错误代码,或者至少是错误的,因为在C应用程序中,它不能处理C++异常。这是真的吗?我通常应该做什么?如果您正在开发将由其他系统使用的组件,是否有处理例外的经验法则。,c++,c,exception-handling,C++,C,Exception Handling" /> 这些函数的内部实现是不暴露的C++类,我假设使用这种样式,DLL可以在C或C++应用程序中使用。 问题是,我不处理任何类型的C++异常(即BADYOLL),而我把这些东西留给了调用方(更高层)。 经过与同事的激烈辩论,我应该捕捉所有异常并返回错误代码,或者至少是错误的,因为在C应用程序中,它不能处理C++异常。这是真的吗?我通常应该做什么?如果您正在开发将由其他系统使用的组件,是否有处理例外的经验法则。,c++,c,exception-handling,C++,C,Exception Handling" />

C程序能否处理C++;例外情况? 我正在开发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(); } #包括 #ifdef导入 #定义DLL u declspec(dllimport) #否则 #定义DLL\uuu declspec(dllexport) #恩迪夫 外部“C”{ DLL bool_u_cdeclinit(); DLL bool_uucdecl Foo(const TCHAR*); DLL bool_u_cdeclrelease(); } P>这些函数的内部实现是不暴露的C++类,我假设使用这种样式,DLL可以在C或C++应用程序中使用。 问题是,我不处理任何类型的C++异常(即BADYOLL),而我把这些东西留给了调用方(更高层)。 经过与同事的激烈辩论,我应该捕捉所有异常并返回错误代码,或者至少是错误的,因为在C应用程序中,它不能处理C++异常。这是真的吗?我通常应该做什么?如果您正在开发将由其他系统使用的组件,是否有处理例外的经验法则。

C程序能否处理C++;例外情况? 我正在开发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(); } #包括 #ifdef导入 #定义DLL u declspec(dllimport) #否则 #定义DLL\uuu declspec(dllexport) #恩迪夫 外部“C”{ DLL bool_u_cdeclinit(); DLL bool_uucdecl Foo(const TCHAR*); DLL bool_u_cdeclrelease(); } P>这些函数的内部实现是不暴露的C++类,我假设使用这种样式,DLL可以在C或C++应用程序中使用。 问题是,我不处理任何类型的C++异常(即BADYOLL),而我把这些东西留给了调用方(更高层)。 经过与同事的激烈辩论,我应该捕捉所有异常并返回错误代码,或者至少是错误的,因为在C应用程序中,它不能处理C++异常。这是真的吗?我通常应该做什么?如果您正在开发将由其他系统使用的组件,是否有处理例外的经验法则。,c++,c,exception-handling,C++,C,Exception Handling,C没有例外,因此,一般来说,您应该捕获所有异常并返回错误代码和/或提供一个函数来返回有关上一个错误的信息。如果这是使用MSVC的Windows,那么您可以在C中捕获异常,但不能很好地捕获它们。C++异常通过OS ABI的结构化异常处理机制来提供,而微软有一个C扩展来处理OS结构异常。请注意,这些包括访问冲突、被零除等,您通常希望终止程序并记录错误报告。您可以通过代码0xe04d533(4D 53 43=MSC)来识别C++异常,并将其余的都投上。 总而言之,您可能不想跨越DLL边界抛出异常,如果

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

如果这是使用MSVC的Windows,那么您可以在C中捕获异常,但不能很好地捕获它们。C++异常通过OS ABI的结构化异常处理机制来提供,而微软有一个C扩展来处理OS结构异常。请注意,这些包括访问冲突、被零除等,您通常希望终止程序并记录错误报告。您可以通过代码0xe04d533(4D 53 43=MSC)来识别C++异常,并将其余的都投上。


总而言之,您可能不想跨越DLL边界抛出异常,如果您只是公开一个C API,当然也不想这样做。

只有在调用方设计用来处理异常时,才会将异常传播给调用方。我猜想,在您的情况下,代码“>终止”(/Calp>)一旦任何异常逃逸C++代码,都会立即调用,因为从C++运行时的观点来看,异常还没有被处理。 COM服务器设计中也会出现同样的情况——客户端可以使用任何语言/技术。规则是任何异常都不应转义COM服务器方法-所有异常都必须在HRESULT和(可选)中捕获和转换。在你的情况下,你也应该这样做


<> > C代码夹在两层C++代码之间。

作为一般规则,你应该<强>绝对/强>允许C++异常传播到模块边界之外。这是因为C++标准没有指定如何实现异常传播,因此这是编译器(和编译器标志)和操作系统相关的。您不能保证调用模块的代码将使用与模块具有相同编译器标志的相同编译器进行编译。事实上,正如您用这个问题演示的那样,您不能保证调用模块的代码将使用相同的语言编写


详情请参阅萨特和Alexandrescu在C++编码标准中的第62项。

< P> OK,因为它被要求:

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);
}
}
#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;
}
#包括
#包括
外部“C”{
void sethandler(void(*func)(void)){std::set_terminate(func);}
int throwingFunc(int arg){
如果(arg==0)
抛出std::bad_cast();
返回(arg-1);
}
}
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);
}
}
#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;
}
#包括
extern int throwingFunc(int arg);
外部void sethandler(void(*func)(void));
void myhandler(void)
{
printf(“调用了处理程序-一定是某个异常?!\n”);
}
int main(int argc,字符**argv)
{
sethandler(myhandler);
printf(“throwingFunc(1)=%d\n”,throwingFunc(1));
printf(“throwingFunc(-1)=%d\n”,throwingFunc(-1));
printf(“throwingFunc(0)=%d\n”,throwingFunc(0));
返回0;
}
当我编译这两个,将它们链接在一起并运行这个(Ubuntu 10.04,gcc 4.4.5,x64),我得到:

美元/xx throwingFunc(1)=0 throwingFunc(-1)=-2 处理程序调用-一定是某个异常?! 流产

这样,虽然您可以从C中捕获异常,但这几乎不足够——因为<>代码> STD::TealEnter()/Cuff>中的C++运行时行为是未定义的,并且因为处理程序没有得到任何状态信息(以消除异常类型和/或源)。处理程序无法清理任何东西


顺便说一句,在本例中,我特意选择了
std::bad_cast()
作为异常类型。这是因为抛出说明了
std::set_unexpected()
std::set_terminate()
之间行为的差异-对于所有非
std::bad*
异常,将调用意外处理程序,而为了捕获标准异常,需要使用终止处理程序。。。看到这个困境了吗?线束太宽而不能实际使用:(

不,C.C++中没有例外的情况,可以登记C链接/<代码>外部C < /COD>函数作为异常异常的处理程序,通过<代码> STD::SETIVNOUND()。如果已知损坏的名称,您可以直接从纯C中调用它。否则,您可以为它公开一个
外部C
包装器。这不是一个方便的界面,而是如果您的库在其自身边界之外污染是绝对不可避免的…@FrankH:这应该是一个答案,而不是一个注释。许多图书馆的ies(如传统fortran库)使用DealBoover方法。@哑巴编码器:不要在实际代码中这样做。好吧,但是如果DLL的客户端是C++应用程序,在DLL边界上传播异常是个好主意吗?艾哈迈德:不,除非你想为每个编译器版本提供DLL。@艾哈迈德:在这种情况下,我会说是,但是很容易——如果你提供了C接口的话。不要使用异常,如果你提供C++接口,你可以。@格奥尔:啊,我总是假设客户端会重新编译源代码;协议。