当我们用C编写程序时,我们可能会调用一些用C ++编写但具有C接口的库。然后,当我们调用这些库时,可能会发生C ++异常。所以我的问题是我们如何处理这种情况。从C ++开发人员的角度来看,我对这个问题更感兴趣。假设我正在开发一个将由C程序调用的C ++库,我应该停止使用异常而不是返回错误代码吗?另一种情况是,如果我已经有一个使用异常的完全开发的C ++库,我怎么能以一种只使用错误返回方法的快速方式传输这个库?
答案 0 :(得分:9)
您必须捕获C ++端的所有异常,并将它们转换为C中的相应错误返回,其中可能包含适当的特定错误代码。这并不意味着您停止使用异常 - 您仍然可以在C ++中使用它们 - 但是您无法将它们暴露给C,它们将成为实现细节。
典型的包装器可以按如下方式构建:
// thingy-wrapper.h, typically included from C code:
#ifdef __cplusplus
extern "C" {
#endif
// create a typedef visible to C that doesn't expose the layout of
// the implementation.
typedef void *thingy_t;
// wrapper for std::string Thingy::get_name()
char *thingy_get_name(thingy_t t);
#ifdef __cplusplus
}
#endif
// thingy-wrapper.cpp, implements the wrapper, compiled with C++:
#include <thingy-wrapper.h>
#include <thingy.hpp> // declares Thingy class
char *thingy_get_name(thingy_t t_)
{
try {
Thingy& t = *static_cast<Thingy*>(t_);
std::string name = t.get_name();
return strdup(name.c_str());
}
catch(...) {
return NULL;
}
}
在这个简单的示例中,thingy_get_name
的调用者可以检测到发生了错误,但无法找出错误的详细信息。更现实的示例将捕获特定的异常,并在返回NULL之前将last_error
变量设置为错误代码或消息。 ...
只会作为最后的手段被捕获,并会将last_error
设置为通用UNKNOWN_ERROR
值。用于查询上一个错误的单独API(例如thingy_last_error()
)可用于thingy_get_name()
的更谨慎的来电者。
错误和非错误结果之间的分离使得不关心错误原因的代码能够简单地检查它是否收到NULL
,同时允许更加尽责的代码正确传播或报告错误。如果您的库是多线程的,请确保last_error
使用线程本地存储。
答案 1 :(得分:4)
然后,当我们调用这些库时,可能会发生C ++异常。所以我的问题是我们如何处理这种情况。
C代码无法处理这种情况。 C代码无法处理C ++异常。
假设我正在开发一个将由C程序调用的C ++库,我应该停止使用异常而不是返回错误代码吗?
没有。如果您希望C ++库使用C ++库,则应使用本机C ++错误处理。这意味着例外。
但是,暴露给C代码的接口不得抛出异常。通常,这意味着编写一个适配器层来捕获C ++库引发的异常,并将它们转换为错误代码以供C代码使用。
另一种情况是,如果我已经有一个使用异常的完全开发的C ++库,我怎么能以一种只使用错误返回方法的快速方式传输这个库?
这里真的没有捷径。您必须编写将C ++异常转换为C错误代码的适配器。如果您希望库为C和C ++消费者公开接口,那么您无论如何都要编写适配器。所以错误处理的方面只是用这个适配器处理的另一件事。
答案 2 :(得分:1)
异常不会被C捕获,所以如果你想捕获它们,那么在C代码或C ++代码中你必须非常仔细地编写包装器。
还要确保在C ++函数中将函数声明为:
extern "C"
您也可以查看How to mix C and C++