我最近已將用C++編寫的Boost Python wraping庫轉換爲C,並使用SWIG封裝來支持更多語言。 我從C++切換到C,因爲庫只包含一組函數,我也希望庫可以從C調用(而不必使用C++編譯器編譯整個程序)。 但是,有一件事不容易移植,一小部分功能需要將錯誤報告回來。 在C++/Boost中,用throw
和異常轉換非常優雅地完成了Python。SWIG最優雅的方式包裝C庫以引發異常
什麼是最優雅的方式(在C語言和包裝語言方面)有一個函數子集報告錯誤?
我最近已將用C++編寫的Boost Python wraping庫轉換爲C,並使用SWIG封裝來支持更多語言。 我從C++切換到C,因爲庫只包含一組函數,我也希望庫可以從C調用(而不必使用C++編譯器編譯整個程序)。 但是,有一件事不容易移植,一小部分功能需要將錯誤報告回來。 在C++/Boost中,用throw
和異常轉換非常優雅地完成了Python。SWIG最優雅的方式包裝C庫以引發異常
什麼是最優雅的方式(在C語言和包裝語言方面)有一個函數子集報告錯誤?
這就是我的做法。 %{...%}塊將其內容插入到包裝文件中。 %例外塊是SWIG的異常處理,並在每次函數調用後運行,以檢查是否有錯誤,並在PyErr_SetString(如果有)時拋出異常。然後,只需撥打「SET_ERR(」錯誤消息「);從你的C函數,如果你想拋出一個異常
%{
/* Exception helpers */
static int swig_c_error_num = 0;
static char swig_c_err_msg[256];
const char *err_occurred()
{
if (swig_c_error_num) {
swig_c_error_num = 0;
return (const char*)swig_c_err_msg;
}
return NULL;
}
void set_err(const char *msg)
{
swig_c_error_num = 1;
strncpy(swig_c_err_msg, msg, 256);
}
%}
%exception {
const char *err;
$action
if (err = err_occurred()) {
PyErr_SetString(PyExc_RuntimeError, err);
return NULL;
}
}
另外,如果你的C庫使用一組標準的返回碼,你可以更換該機制在%異常塊中檢查函數的返回代碼。
%exception {
int rc;
rc = $action;
if (rc == ERR) {
PyErr_SetString(PyExc_RuntimeError, <err msg>);
return NULL;
}
}
請看Richard R. Hanson在C語言接口和實現中的第4章。