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__

#include 

typedef 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对象返回给脚本。

标签: python

添加新评论