python 调用 C
一个python脚本,需要调用到一个加解密算法的encode。算法已有C实现。
无心去研究清楚算法的具体实现,于是想到了python直接调用C。
python自带开发支持,以MAC OS X环境为例(linux,unix实现基本相同)。
系统自带python2.7
1、新建一文件,名为pyXXX.c
#include#include "XXX.h" PyObject *wrap_encode(PyObject* self, PyObject* args) { ByteArray *inArray = (ByteArray *)malloc(sizeof(ByteArray)); //s# (string, Unicode or any read buffer compatible object) if (!PyArg_ParseTuple(args, "s#", &inArray->data, &inArray->len)) { free(inArray); return NULL; } ByteArray *outArray = XXX_encodeDefaultKey(inArray); free(inArray); if (NULL == outArray) { printf("==XXX encode fail, check the buffer size!"); return NULL; } PyObject *rtn = Py_BuildValue("s#", outArray->data, outArray->len); free(outArray->data); free(outArray); return rtn; } static PyMethodDef XXXMethods[] = { {"encodeDefault", wrap_encode, METH_VARARGS, "encode by defaultKey"}, {NULL, NULL} }; void initXXX() { PyObject *m; m = Py_InitModule("XXX", XXXMethods); }
2、XXX.h 和 XXX.c的移植
由于编译使用gcc,而且为了在64位系统上运行正确,需要把基础类型都换过来。
修改基础数据类型为int32_t等等。
XXX.h
#ifndef __XXX_h__ #define __XXX_h__ #includetypedef struct __ByteArray { int len; unsigned char *data; } ByteArray; ByteArray *XXX_encodeDefaultKey(ByteArray *value); #endif
XXX.c
#include#include #include #include "XXX.h" ByteArray *XXX_encodeDefaultKey(ByteArray *value) { // for test only ByteArray *newCode = (ByteArray *)malloc(sizeof(ByteArray)); newCode->len = 10; newCode->data = (unsigned char *)malloc(newCode->len); return newCode; }
3、编译
python的头文件和库分别在
/usr/include/python2.7
/usr/lib/python2.7/config
编译命令Linux
#gcc -fPIC XXX.c pyXXX.c -o XXX.so -shared -I/usr/include/python2.7 -L/usr/lib/python2.7/config -lpython2.7
编译命令Mac
gcc -shared xxtea.c pyxxtea.c -o xxtea.so -framework Python
win32编译参考:https://my.oschina.net/yushulx/blog/420097
4、py脚本中调用测试
把生成的xxx.o和 py放在同一目录
import XXX return XXX.encodeDefault(buff)
注意事项:最终我们用的是import XXX,这决定了几个C函数名称和变量名称。
否则import会失败。如下:
- void initXXX()
- Py_InitModule("XXX", XXXMethods)
- static PyMethodDef XXXMethods[] =
5、PyArg_ParseTuple 与 Py_BuildValue
PyArg_ParseTuple解析从py脚本传递过来的参数,转换为C数据类型。
"s#"是这里需要用到的,官方文档的解释如下:
s# (string, Unicode or any read buffer compatible object)
所以它适合从文件读取的二进制数据。
Py_BuildValue反向build出一个py对象返回给脚本。