我爱编程

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

2018-01-04  本文已影响0人  海子xxh

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}

!!!大功告成!!!

上一篇下一篇

猜你喜欢

热点阅读