Python访问C程序
最近碰到了Python调用C++代码的需求,c++代码需要先导出C接口才能给Python调用,本质上解决python调用C代码就行了
假如我需要导出我的这两个C函数
int fab(int n)
{
if (n == 1 || n == 0)
return 1;
else
return n * fab(n - 1);
}
void quick_sort(int arr[], int left, int right)
{
int i, j, temp, pivot;
if (left < right)
{
i = left;
j = right;
pivot = arr[(left + right) / 2];
while (i <= j)
{
while (arr[i] < pivot)
{
i++;
}
while (arr[j] > pivot)
{
j--;
}
if (i <= j)
{
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
i++;
j--;
}
}
quick_sort(arr, left, j);
quick_sort(arr, i, right);
}
}
需要如下一些步骤
- 导出Python.h头文件,这个文件需要安装python3-env动态库
- 定义模块
- 模块中配置要导出的接口
- 在接口中将python类型解析成C类型
- 编译成so
- python中引入模块,调用接口
定义了模块的init函数以及模块的名字和usage信息
static struct PyModuleDef moduleExport = {
PyModuleDef_HEAD_INIT,
"moduleExport",
"usage",
-1,
exportFunctions};
PyMODINIT_FUNC PyInit_moduleExport(void)
{
return PyModule_Create(&moduleExport);
}
定义模块导出函数,对于每个要导出的函数要指定在python中符号的名字
static PyMethodDef exportFunctions[] =
{
{"fab", wrap_fab, METH_VARARGS, "Caculate N!"},
{"sort", wrap_quick_sort, METH_VARARGS, "排序!"},
{NULL, NULL}};
类型转换
PyObject *wrap_fab(PyObject *self, PyObject *args)
{
int n, result;
if (!PyArg_ParseTuple(args, "i:fab", &n))
return NULL;
result = fab(n);
return Py_BuildValue("i", result);
}
从arg中解析得到list,申请一块内存,将list中的数据拷贝到内存中,完毕后创建一个新list,将结果拷贝到新的list中并返回,这里如果直接返回旧的list会segment fault。
PyObject *wrap_quick_sort(PyObject *self, PyObject *args)
{
PyObject *my_list;
if (!PyArg_ParseTuple(args, "O", &my_list))
{
return NULL;
}
if (!PyList_Check(my_list))
{
PyErr_SetString(PyExc_TypeError, "Expected a list");
return NULL;
}
int list_size = PyList_Size(my_list);
int *my_array = malloc(sizeof(int) * list_size);
for (int i = 0; i < list_size; i++)
{
PyObject *item = PyList_GetItem(my_list, i);
if (!PyLong_Check(item))
{
PyErr_SetString(PyExc_TypeError, "List must contain integers");
return NULL;
}
my_array[i] = PyLong_AsLong(item);
}
quick_sort(my_array, 0, list_size - 1);
my_list = PyList_New(list_size);
for (int i = 0; i < list_size; i++)
{
PyList_SetItem(my_list, i, Py_BuildValue("i", my_array[i]));
}
free(my_array);
return my_list;
}
使用这个命令编译,动态库的名字得和你的模块名匹配,这里有三个名字要匹配,一个是模块名,一个是动态库名,最后是PyInit_xxxx
gcc -fPIC hello.c -o moduleExport.so -shared -I/usr/include/python3.8
python中直接调用
import moduleExport
print(moduleExport.fab(10))
res = moduleExport.sort([1,3,2])
print(res)