转载:http://blog.csdn.net/chgaowei/article/details/7467632
1、 可以使用swig来创建c 的扩展程序,非常方便。目前没有时间研究内部机制,先暂时使用,后面在研究吧。
2、 swig使用步骤:为库的头文件建立.i文件:
%{
/* Includes theheader in the wrapper code */
#include"code.h"
#include"sip.h"
%}
/* Parse theheader file to generate wrappers */
%include"code.h"
%include"sip.h"
3、 使用swig命令生成py脚本及对应的C文件:swig –python sip.i。
4、 将生成的c源文件放到c扩展库中进行编译。
5、 这里有一个要注意:生成的动态链接库,必须是_sip.so,否则无法调用。swig是写死的。_sip.so需要拷贝到:/usr/local/lib/python2.7/site-packages/路径下。
6、 Makefile文件中,对于库引用的其他的库,必须显示的指出,否则Python无法找到对应的库。
7、 如何在c的扩展库中调用Python的函数——将c扩展库的回调函数设置为python函数:
swig是不支持直接在c的扩展库中调用Python函数的。它只支持将C的接口作为回调函数设置给c的库。
实现这个功能需要利用Python的c API和ctypes来实现。
Python c 的api包含一系列的函数:
PyCallable_Check:检查对象是否可调用;
PyArg_ParseTuple:解析参数列表,将Python参数解析为c;
PyEval_CallObject:调用对象;
Py_BuildValue:将c变量打包为Python的参数对象。
好了,有这些就足够了。
假设c库中有一个设置回调函数接口:
void set_callback_fun(void(*fun)(int, int , int))
{
}
下面是c扩展库中要添加的代码:
//全局变量,保存Python中要回调的可调用对象。
static PyObject*gCallbackFun = NULL;
//调用上面函数设置的python脚本函数
//Python可调用对象的转换函数,转化为C的调用方式
static voidcallbacfun(int type,int chn,int dataType)
{
PyObject* pArgs = NULL;
PyObject* pRetVal = NULL;
int nRetVal = 0;
pArgs = Py_BuildValue("(i, i,i)", type, chn, dataType);//将c的参数转化为Python的参数对象
pRetVal = PyEval_CallObject(gCallbackFun,pArgs);//调用Python的可调用对象。
Py_DECREF(pArgs);
Py_DECREF(pRetVal);
}
/// set_callback_fun函数的包装函数
static PyObject*wrap_set_callback_fun(PyObject *dummy, PyObject *args)
{
PyObject *temp = NULL;
if (PyArg_ParseTuple(args, "O:set_callback_fun",&temp)) {//获取Python对象
if (!PyCallable_Check(temp)) {//检查对象是否可以调用
PyErr_SetString(PyExc_TypeError,"parameter must be callable");
}
Py_XINCREF(temp); /* Add a reference to new callback */
Py_XDECREF(gCallbackFun); /* Dispose ofprevious callback */
gCallbackFun = temp; /* 保存回调对象 */
}
set_callback_fun(callbacfun);//注意,这里掉一下包,用一个C的函数注册到c库中。
return Py_BuildValue("i",(gCallbackFun == NULL) ? 0 : 1);
}
注意:如果对象不可调用,会段错误。后面要解决一下。
Python代码:
CBFUNC =CFUNCTYPE(c_int, c_int, c_int, c_int)//创建一个c函数类型的对象工厂,该函数返回值为int,有三个入参,都为int。
callbakFunc = CBFUNC(pyFun)//根据Python可调用对象生成函数。
set_callback_fun(callbakFunc)//设置回调函数
注意:pyFun必须要有返回值。否则会报异常。
另外,我发现,不用CFUNCTYPE来生产c回调函数,直接用pyFun,也是可以的。至于区别,后面在研究一下吧,要写代码了。
几个异常问题:1、一个可以使用CFUNCTYPE,但是一个一使用它就段错误。2、回调函数可以不返回值,也是可以的。但是一个不返回就不可以。
在Python中使用c扩展时向C传递数组:
8、 如果一个函数的参数是一个数组(指针),Python如何传递?下面的方法是可以直接传递列表。把这个加到.i文件中。
%{
static intconvert_darray(PyObject *input, int *ptr, int size) {
int i;
if (!PySequence_Check(input)) {
PyErr_SetString(PyExc_TypeError,"Expecting a sequence");
return 0;
}
if (PyObject_Length(input) != size) {
PyErr_SetString(PyExc_ValueError,"Sequencesize mismatch");
return 0;
}
for (i =0; i < size; i++) {
PyObject *o =PySequence_GetItem(input,i);
if (!PyFloat_Check(o)) {
Py_XDECREF(o);
PyErr_SetString(PyExc_ValueError,"Expecting a sequence offloats");
return 0;
}
ptr[i] = PyFloat_AsDouble(o);
Py_DECREF(o);
}
return 1;
}
%}
%typemap(in) int[ANY](int temp[$1_dim0]) {
if (!convert_darray($input,temp,$1_dim0)) {
return NULL;
}
$1 = &temp[0];
}
9、 如果一个结构体中有一个int类型数组,应该如何赋值?
在.i中增加下面代码:
%include"carrays.i"
%array_class(int,intArray);
在Python中申请数组:
a = intArray(10),将A复制给数组成员即可。