python调用c++动态库 类_python调用c++模块.so库, 互相回传数据(ctypes、pybind11)

如题,最近遇到c++与python模块混合协作的任务。在python端调用c++模块编译好的.so库,c++中得到的string结果,需要返回给python端。咋一看是一个混合编程问题,或者说,需要进行c++与python通信。哇其实我的需求好像没那么高大上,就简单的捣鼓了下python中的ctypes库,大概可以满足需求。

数据交流嘛,有进就要有出啊。我的上一篇笔记记录了怎么把python中的数据送进c++,.npy或者直接从内存传输都可以,感兴趣的小伙伴可以看看~.~ ChenJ:huffman 霍夫曼无损编解码 c++ 压缩

那么对于c++中的结果怎么输出,下面简单记录下,两种方法:

1.在python端,传入一个,可修改指针指向内容的指针。

Py端:

import ctypes

from ctypes import *

ll = ctypes.cdll.LoadLibrary

lib = ll("good.so")

lib.fun.restype = c_char_p # restype定义返回类型, 可被修改.

lib.fun.argtypes = [c_char_p] # argtypes定义输入参数的类型,是个char型指针

# create_string_buffer() 注意此函数的使用..

str_buf = create_string_buffer("test".encode('utf-8')) # 没改变前的str_buf内容是:”test“

s = lib.fun(str_buf); # str_buf是传进来是一个char型指针. 可供c++中改变string内容. 调用c++中的fun()函数

print("here is python: ", s) # s为被修改后的string值

C++端:

extern "C"

const char *fun(char* tmp){

static string res = "something"; // s为在c++端生成的string结果.

// 将s与tmp"叠加",从而在py端通过tmp的指针,访问到改变内容后的string结果 res += tmp;

return res.c_str(); // .c_str()获取string的指针}

2.在python端送入一个string变量,让它在c++中直接被修改,就不用再另外做返回后的解析工作。这样做需要注意的地方是,python中的string,一个元素占4byte(python3)。所以要注意下差别处理。

Py端:

import ctypes

from ctypes import *

ll = ctypes.cdll.LoadLibrary

lib = ll("good.so")

str_res = "goodjob"

p=c_wchar_p(str_res) # c_wchar_p: ctypes中指向string的指针

lib.fun(p,len(str_res)) # p直接传入,其指向的string将在c++中被修改

print(p.value)

C++端:

void fun(char* p, int len){

/* your code */

string tmp_res = "something"; // tmp_res是即将要赋值给python端的,在c++中的计算结果 for(int i=0;i

p[i*4]=tmp_res[i]; // py中,string一个元素占4btye,所以p[4*i]

}

以上两种方法都亲测有效的,小伙伴们可以放心"服用"。

但...是,如果c++模块得到的string结果中,包含一些"特殊"char,在py端就会有奇怪的东西返回。比如第一种方法, .c_str()函数可能无法正确获取到修改后的 string 的指针。第二种方法的话,return的string可能被截断或者为空 (可能c++的结果string中包含一些提前结束的"信号"???)

我就遇到了上述问题,解决方式是:”曲线救国“吧,在含有"特殊"char的上一步,把中间结果传到py端先,再在py端做进一步处理。这个法子不一定适合所有场景的,或许你还可以试试把char转个ascll码再传出???

----------------------------------------- 20200915 更新 ---------------------------------

以上提到的两种方法我都试过了,繁琐且低效。这里给大家推荐一个神器:pybind11!

pybind11 直接支持: 在python端传入list或numpy数据,c++中计算得到的vector或string结果也可以便捷传出,忒棒了!

给个示例:

c++:

class ContainerTest{

public:

ContainerTest(){}

void Set(vector input_s ){ // input_s接收python传进来的数据,支持npy或list等 s = input_s; // 把python端传进来的vector赋值给mv }

/*************** your fun **************/

vector Fun(){

/** some code **/

return result; // vector类型的哈,在python端就直接变成list了}

private:

vector s; // 这里“声明”下s};

PYBIND11_MODULE(py2cpp, m){

m.doc() = "pybind11 example";

pybind11::class_(m, "CT" )

.def( pybind11::init() )

.def( "set", &ContainerTest::Set ) // ""内的是暴露给python的函数名 .def( "fun", &ContainerTest::Fun );

}

编译cpp :

g++ -O3 -Wall -shared -std=c++11 -fPIC `python3 -m pybind11 --includes` your.cpp -o py2cpp`python3-config --extension-suffix` -I /usr/include/python3.6m

py:

import py2cpp # 编译上面的cpp文件,即可得到这个.so库

c=py2cpp.CT()

c.set(npy_data) # pybind11可支持npy

strat = time.time()

res = c.fun()

print(res)

希望遇到类似问题的小伙伴们也一样可以愉快解决! 看都看完了,点个赞再走呗~.~

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值