C代码中的C++异常处理

C++ exception handling in C codes

本文关键字:C++ 异常处理 代码      更新时间:2023-10-16

当我们用C编写程序时,我们可能会调用一些用C++编写但有C接口的库。然后,当我们调用这些库时,可能会发生C++异常。所以我的问题是我们如何处理这种情况。从C++开发人员的角度来看,我对这个问题更感兴趣。假设我正在开发一个C程序将调用的C++库,我是否应该停止使用异常并返回错误代码?另一种情况是,如果我已经有了一个完全开发的使用异常的C++库,我如何才能以只使用错误返回方法的快速方式传输这个库?

您必须捕获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使用线程本地存储。

然后,当我们调用这些库时,可能会发生C++异常。所以我的问题是我们如何处理这种情况。

C代码无法处理这种情况。C代码不能处理C++异常。

假设我正在开发一个C程序将调用的C++库,我是否应该停止使用异常并返回错误代码?

没有。如果您希望C++库由C++代码使用,则应该使用本机C++错误处理。这意味着例外。

但是,您向C代码公开的接口不能引发异常。通常,这意味着编写一个适配器层,捕获C++库引发的异常,并将其转换为C代码使用的错误代码。

另一种情况是,如果我已经有了一个完全开发的使用异常的C++库,我如何才能以只使用错误返回方法的快速方式传输这个库?

这里真的没有捷径可走。您必须编写将C++异常转换为C错误代码的适配器。如果您希望库为C和C++使用者公开接口,那么您无论如何都要编写一个适配器。因此,错误处理只是这个适配器需要处理的另一件事。

异常在C中没有被捕获,所以如果你想捕获它们,那么在你的C代码或C++代码中,你必须非常小心地编写包装器。

还要确保在您的C++函数中,您的函数声明为:

extern "C"

您也可以查看如何混合C和C++