我正在尝试替换 MATLAB/MEX 并切换到 Python。我遇到了 SWIG、ctypes 和 Cython 作为可能的解决方案,并开始尝试 SWIG(这看起来很简单)。
我的 C 函数具有可变参数长度的形式main(int argc, char *argv[])
。我在网上找到了解决方案,但是与 SWIG 一起使用会导致很多问题。
- 其他方法(ctypes / Cython)更简单吗?
- 使用 SWIG 完成此任务的任何示例都会有所帮助。
在 SWIG 文档中实际上有一个示例,用于使用 Python 实现这种功能。我在这里引用了它,并做了一个小的改动:
%typemap(in) (int argc, char *argv[]) { int i; if (!PyList_Check($input)) { PyErr_SetString(PyExc_ValueError, "Expecting a list"); return NULL; } $1 = PyList_Size($input); $2 = (char **) malloc(($1+1)*sizeof(char *)); for (i = 0; i < $1; i++) { PyObject *s = PyList_GetItem($input,i); if (!PyString_Check(s)) { free($2); PyErr_SetString(PyExc_ValueError, "List items must be strings"); return NULL; } $2[i] = PyString_AsString(s); } $2[i] = 0; } %typemap(freearg) (int argc, char *argv[]) { free($2); // If here is uneeded, free(NULL) is legal }
这使您可以在 Python 中简单地执行以下操作:
import test
test.foo(["a", "b", "c"])
test
您给 SWIG 的模块名称在哪里,并且foo
是与签名匹配的函数int argc, char *argv[]
。对于 Python 程序员来说使用简单直观,它封装并重用了复杂的位。
但是文档似乎没有提到的是,有一个接口文件已经为您完成了所有这些工作:
%module test
%include <argcargv.i>
%apply (int ARGC, char **ARGV) { (int argc, char *argv[]) }
void foo(int argc, char *argv[]);
足够了。
这是使用 ctypes 的示例。
首先是c代码,它不能改变argv的内容:
#include <stdio.h>
void test(int n, char *argv[])
{
int i;
for(i=0;i<n;i++)
{
printf("%s\n", argv[i]);
}
}
然后你可以通过下面的python代码调用这个c函数:
from ctypes import *
dll = cdll.LoadLibrary("charpp_test.dll")
argv = ["test1", "testtest2", "testtesttest3"]
dll.test(len(argv), (c_char_p*len(argv))(*argv))