美文网首页我爱编程
Python调用C/C++函数(2017-12-23)

Python调用C/C++函数(2017-12-23)

作者: 海子xxh | 来源:发表于2018-01-04 10:59 被阅读0次

    1、已有资料整理

    (1)封装步骤介绍:https://www.cnblogs.com/dchipnau/p/5296728.html

    (2)数据类型对照:https://www.cnblogs.com/btchenguang/archive/2012/09/04/2670849.html

    (3)C++调用Python类型:https://www.ibm.com/developerworks/cn/linux/l-pythc/

    (4)Python官网文档:https://docs.python.org/2.7/c-api/list.html

    2、编程步骤如下:

    (1)基本要求:

    A、VS2015编译器:

    B、Python2.7以上:

    (2)c++文档:glmgen.cpp


    #include "C:\\anaconda2\\include\Python.h"

    #pragma comment(lib, "C:\\anaconda2\\libs\\python27.lib")

    #include<string.h>

    #include<stdlib.h>

    #include "utils.h"

    ##include <math.h>

    //原始函数(一):glmgen_factorial

    double glmgen_factorial(int n)

    {

    int i = 0;

    double x = 1;

    for (i = 2; i <= n; i++) {

    x *= i;

    }

    return x;

    }

    //原始函数(二):l1norm

    double l1norm(double * x, int n) {

      int i;

      double s;

      s = 0;

      for (i = 0; i < n; i++)

      {

      s += fabs(x[i]);

      }

      return s;

    }

    //封装一:数据类型转换

    #ifdef __cplusplus

    extern "C" {

    #endif

    PyObject* glmgen_glmgen_factorial(PyObject* self, PyObject* args)

    {

    int n, result;

    if (!PyArg_ParseTuple(args, "i", &n))

    return NULL;

    result = glmgen_factorial(n);

    return Py_BuildValue("i", result);

    }

    PyObject* glmgen_l1norm(PyObject* self, PyObject* args)

    {

    int i, n;

    double x[3], result;

    char* y;

    char* pch;

    //返回的是list:

    PyObject* pList = PyList_New(3);

    assert(PyList_Check(pList));

    //返回的是dict:

    PyObject* pDict = PyDict_New();

    assert(PyDict_Check(pDict));

    if (!PyArg_ParseTuple(args, "si", &y, &n))

    return NULL;

    i = 0;

    pch = strtok(strdup(y), ",");

    while (pch != NULL)

    {

    x[i] = atof(pch);

    pch = strtok(NULL, ",");

    PyList_SetItem(pList, i, Py_BuildValue("d", x[i]));

    i++;

    }

    PyDict_SetItemString(pDict, "x_data", pList);

    PyDict_SetItemString(pDict, "l1norm_data", Py_BuildValue("d", result = l1norm(&x, n)));

    return pDict;

    Py_DECREF(pList);

    Py_DECREF(pDict);

    }

    //函数数组

    static PyMethodDef glmgenMethods[] =

    {

    { "glmgen_factorial", glmgen_glmgen_factorial, METH_VARARGS, "Caculate N!" },

    { "l1norm", glmgen_l1norm, METH_VARARGS, "Caculate l1norm" },

    { NULL, NULL }

    };

    //函数初始化

    __declspec(dllexport) void initglmgen()

    {

    PyObject* m;

    m = Py_InitModule("glmgen", glmgenMethods);

    }

    #ifdef  __cplusplus 

    }

    #endif 

    注意:

    A、代码块

    #ifdef __cplusplus

    extern "C" {

    #endif

    /*

    something need to calculates

    */

    #ifdef  __cplusplus 

    }

    #endif 

    这是必须要的,解决c++编译c出现的问题。

    B、由于Pyhton本身是C语言编译的,二者互调时,相当于c++里面的指针变量都指向Python传入的数据,一旦在C++中改变,原始数据也会变化,因此,需要返回原始数据时,需要复制原始数据(使用函数strdup(y))。

    C、返回类型为C++类型时,需要在函数返回类型前加__declspec(dllexport) 。

    D、声明的动态变量、中间变量、存储返回变量记得释放内存:Py_DECREF(pList)。

    E、传入整数(double、string、char、char *),可以直接使用 PyArg_ParseTuple(args, "si", &y, &n)、Py_BuildValue("d", x[i]);当使用列表、字典、元组等Python类型时,需要在Python中转化为字符串,以字符串形式传入C++,然后在C++中转为C++类型。本办法虽笨,但很实用。对于传回Python的,无需做相应转化,只要在Python中使用相应方法即可,具体参见引文(3)、(4)。

    最后将上述代码编译为:glmgen.pyd(即为glmgen.dll)

    3、Python代码

    from glmgen import *

    #----将列表转化为字符串

    def list2str(list_data):

        return ','.join([str(i)for i in list_data])

    #调用C++函数

    x= glmgen_factorial(8)

    ls1= [1,2,3]

    ls2= util.list2str(ls1)

    t= l1norm(ls2,3)

    print ls2,t

    输出:

    1,2,3 {'x_data': [1.0, 2.0, 3.0], 'l1norm_data': 6.0}

    !!!大功告成!!!

    相关文章

      网友评论

        本文标题:Python调用C/C++函数(2017-12-23)

        本文链接:https://www.haomeiwen.com/subject/zmfcgxtx.html