我定義了一個struct a { }
。我的C函數通過引用獲取一個數組struct a
,然後填充它中的數據。所以它接受一個參數struct a **
。我想使用SWIG接口從Python中調用此函數。有沒有辦法做到這一點?包裝一個需要指針數組的函數
1
A
回答
4
你可以用SWIG和Python來做到這一點。我已經設置了以下test.h文件deomstrate:
struct a {
int val;
};
static void populate(struct a **list) {
int count = 0;
// Terminate when NULL entry found
while (*list) {
(*list)->val = count++;
++list;
}
}
的填入功能需要你描述一個struct a**
,假設列表爲空終止,並做一些事情到列表中的每個元素。
我選擇公開此對Python的辦法是爲取整數,即列表的大小一起工作,然後返回結果列表的功能,因爲這是映射的語義的最好方式「通過論點返回」在我看來是成立的。
我建立一個基本模塊的文件:
%module test
%{
#include "test.h"
%}
然後加入基於指定給Python函數的大小準備的輸入表類型表:
%typemap(in,numinputs=1) struct a ** (int len=0) {
len = (int)PyInt_AsLong($input);
$1 = malloc(sizeof(struct a*)*(len+1));
$1[len] = NULL;
for (int i = 0; i < len; ++i) {
$1[i] = malloc(sizeof(struct a));
}
}
基本上它將該參數作爲整數,爲指針數組分配內存,然後爲元素自己指向的對象分配內存。 (我分別分配它們,以便SWIG/Python可以單獨處理每個項目的引用計數,這比爲所有元素分配一個塊更簡單)
隨着該類型地圖寫入,我添加了另一個類型地圖,它負責同時調用函數的結果,並將其轉換回成PyList:
%typemap(argout) struct a ** {
// Push into PyList for return
$result = PyList_New(len$argnum);
for (int i = 0; i < len$argnum; ++i) {
PyObject *element = SWIG_NewPointerObj(SWIG_as_voidptr($1[i]), SWIGTYPE_p_a, SWIG_POINTER_OWN);
PyList_SET_ITEM($result, i, element);
}
}
這需要我們在在類型映射創建的len
變量的優勢,但因爲它的NULL結束,我們可能只是重新計數長度。然後我們使用包裝對象(由SWIG/Python擁有)填充每個struct a
的Python列表中的每個項目,我們將其傳遞給populate
函數。請注意,如果類型名稱不同,則需要將SWIGTYPE_p_a
更改爲合適的SWIGTYPE
。 (這些可以從生成的包裝源中找到)。
最後,我們需要去分配我們不得不對C面列表中的內存,搭配:
%typemap(freearg) struct a ** {
free($1);
}
,然後問SWIG包住頭文件本身,使用這些typemaps:
%include "test.h"
我編這個有:
swig -python -Wall test.i gcc -Wall -Wextra test_wrap.c -I/usr/include/python2.6 -o _test.so -std=c99 -shared
,然後運行以下Python來檢查:
import test
r=test.populate(100)
print r[0].val
幾點需要從這個例子說明:
- 沒有錯誤檢查,例如
test.populate("Hello world")
會做壞事,PyList_New
可能會失敗,如果沒有失敗,我們需要釋放的各個元素,不只是名單 - 如果內存所有權的語義是不同的,那麼你就需要改變
SWIG_POINTER_OWN
適當 - 如果你不希望有對Python的interfa指定列表的大小(例如,它是已知的或以其他方式修正的),您可以將
numinputs=1
更改爲0,並相應地在typemap中設置0。 - 如果你的函數將列表和一個整數,它的長度,而不是使用NULL結束列表,你可以這樣延伸到multi-argument typemap。
編譯/運行這個例子所需的所有代碼都包含在這個答案,但如果你想在一個方便的壓縮包,我也把它on my site。即使該鏈接應該突破,答案仍然有效。
相關問題
- 1. 指針指向一個函數,需要指針參數
- 2. 函數指針指向一個函數指針的函數
- 3. 從C函數返回的指針數組的C++包裝器
- 4. 需要一些幫助,初始化指向成員函數的指針數組
- 5. 非成員函數需要通過指針打印出一個數組
- 6. 從主指針函數中打印出一個指針數組
- 7. 一個指針數組的指針
- 8. 指針傳遞到一個數組的數組的函數
- 9. C++顯式構造函數,需要一個指針
- 10. C++通過函數指針指向另一個函數指針
- 11. 使用函數指針結構的C中的包裝函數
- 12. 我需要檢查一個指針是否指向一個math.h函數
- 13. 函數指針 - 參數傳遞給一個函數指針
- 14. 如何寫一個函數指針返回一個函數指針函數?
- 15. 用另一個函數包裝一個tornado.gen.engine包裝的函數
- 16. C++函數指針函數,需要模板作爲參數
- 17. 函數指針數組指針用作函數的返回值
- 18. 函數指針等於函數中的另一個指針,爲什麼需要添加*
- 19. 指針數組和指針指向一個數組在C++
- 20. 傳遞一個指向字符數組的指針到函數
- 21. 投一個函數指針
- 22. Malloc函數指針數組
- 23. 數組指針函數
- 24. 函數指針數組
- 25. 指針函數與數組
- 26. 創建一個函數指針,它將一個函數指針作爲參數
- 27. 調用一個dll函數,需要一個指針從python的句柄(win32)
- 28. 從一個指針數組
- 29. 使用函數對象雖然函數指針需要
- 30. 設置指向指針的數組,指向另一個數組中的指針
感謝您的回答。我希望兩天前我已經找到了這個問題/答案。我不得不開發類似的東西,並提出與您幾乎相同的解決方案。另一個教訓是,大多數技術問題已經在之前解決了...... – 2014-08-07 09:27:12