找回密码
 会员注册
查看: 25|回复: 0

Python通过Ctypes调用C++类,实测有效

[复制链接]

5

主题

0

回帖

16

积分

新手上路

积分
16
发表于 2024-9-10 00:29:42 | 显示全部楼层 |阅读模式
文章目录前言创建vsdll工程添加外部库编辑代码编译测试参考前言在软件开发中,有时候需要Python与C++相结合,以充分发挥两者的优势。Python作为一种高级编程语言,具有简洁易读的特点,适用于快速开发和原型设计。而C++则是一种性能强大的编程语言,适用于需要高效率和底层控制的场景。Python调用C++代码的主要方式是使用Cython、ctypes或SWIG等工具。其中,Cython是一种混合语言,允许将Python代码与C语言结合,通过编写类型声明来提高性能。而ctypes是Python标准库中的一部分,允许Python直接调用C函数,并处理C数据类型。另外,SWIG(SimplifiedWrapperandInterfaceGenerator)是一个自动生成Python和其他语言之间的接口代码的工具,使Python可以调用C++代码。在实际应用中,Python调用C++的场景包括但不限于:加速Python程序的关键部分、调用现有的C++库以利用其功能、优化某些算法以提高性能等。通过将Python与C++相结合,开发人员可以在保持Python代码易读性和开发效率的同时,充分发挥C++的性能优势,实现更加复杂和高效的应用程序。Python通过ctypes调用C++代码是一种常见的技术,它提供了一种简单而直接的方法,让Python与C++进行交互。ctypes是Python标准库的一部分,允许Python代码调用动态链接库(DLL)中的C函数,并处理C数据类型。虽然ctypes主要设计用于调用C函数,但也可以用于调用C++代码,只需注意一些特殊的注意事项。要在Python中通过ctypes调用C++代码,首先需要确保将C++代码编译为动态链接库,以便Python能够加载并调用其中的函数。然后,需要在Python中定义与C++函数相对应的函数原型,并在调用时传递正确的参数和返回类型。此外,需要注意C++代码中的名称修饰(namemangling)以及C++异常处理等问题,确保与Python的交互能够顺利进行。在实际应用中,Python通过ctypes调用C++代码的场景包括但不限于:利用现有的C++库实现特定功能、加速Python程序的关键部分、与C++库进行交互以实现复杂的功能等。通过使用ctypes,开发人员可以在Python中利用C++的性能优势,同时保持Python代码的简洁性和易读性。然而,虽然ctypes提供了一种方便的方法来调用C++代码,但它并不是最高效的方法,特别是对于复杂的数据结构和函数签名而言。对于更复杂的场景,可以考虑使用Cython或SWIG等工具,它们提供了更强大和灵活的功能,以便更好地集成Python和C++代码。因此,Python通过ctypes调用C++代码是一种简单而有效的方法,适用于许多场景。通过正确地处理数据类型和函数签名,并注意到C++与Python之间的差异,开发人员可以轻松地在两种语言之间进行交互,实现更加强大和灵活的应用程序。创建vsdll工程添加外部库参考:vs2019添加使用外置库的设置编辑代码添加自己写的C++类Foo.h#pragmaonce#ifndef_pro_header_#define_pro_header_#ifdefEXPORT_PRO_DLL//如果引用此头文件有预定义为EXPORT_PRO_DLL#definePRO_API__declspec(dllexport)#else#definePRO_API__declspec(dllimport)#endifclassFoo{public:Foo(intn);~Foo();voidbar();doubleadd(doublex);int*foobar(intn);private:intval;};extern"C"{PRO_APIFoo*Foo_new(intn)RO_APIvoidFoo_bar(Foo*foo)RO_APIint*Foo_foobar(Foo*foo,intn)RO_APIdoubleFoo_add(Foo*foo,doublex)RO_APIvoiddel_Foo(Foo*foo);}#endif12345678910111213141516171819202122232425262728293031323334Foo.cpp#defineEXPORT_PRO_DLL#include"pch.h"#include"Foo.h"#include"string.h"#includeusingnamespacestd;Foo::Foo(intn){this->val=n;}voidFoo::bar(){std::cout<< "Value is " << this->val<< std::endl; } Foo::~Foo() { cout << "delete foo" << endl; } int* Foo::foobar(int n) { int* data = new int[2]; data[0] = 1 + n; data[1] = 2 + n; return data; } double Foo::add(double x) { return x + this->val;}voiddel_Foo(Foo*foo){deletefoo;}Foo*Foo_new(intn){returnnewFoo(n);}voidFoo_bar(Foo*foo){foo->bar();}int*Foo_foobar(Foo*foo,intn){returnfoo->foobar(n);}doubleFoo_add(Foo*foo,doublex){returnfoo->add(x);}1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859编译测试fromctypesimport*importnumpyasnplib=cdll.LoadLibrary(r"路径\Foo\x64\Debug\Foo.dll")classFoo(object):def__init__(self,n):lib.Foo_new.argtypes=[c_int]lib.Foo_new.restype=c_void_plib.Foo_bar.argtypes=[c_void_p]lib.Foo_bar.restype=c_void_plib.Foo_foobar.argtypes=[c_void_p,c_int]lib.Foo_foobar.restype=POINTER(c_int)lib.Foo_add.argtypes=[c_void_p,c_double]lib.Foo_add.restype=c_doublelib.del_Foo.argtypes=[c_void_p]lib.del_Foo.restype=c_void_pself.obj=lib.Foo_new(n)def__del__(self):lib.del_Foo(self.obj)#析构函数defbar(self):lib.Foo_bar(self.obj)defadd(self,x):returnlib.Foo_add(self.obj,x)deffoobar(self,n):returnlib.Foo_foobar(self.obj,n)if__name__=='__main__':f=Foo(5)f.bar()data_addr=f.foobar(5)array=np.ctypeslib.as_array(data_addr,shape=(2,))#不能通过len计算一维数组的元素个数,进一步需要通过函数传过来print(array)print(f.add(12))12345678910111213141516171819202122232425262728293031323334353637383940414243Ctypes类型注意:字符串、数组和自定义数据类型需要通过地址来实现C和Python之间的数据传递,其他数据看下表。Tips:用数据类型的视角去看C++的类,那么类中的方法或者属性可以看成函数中的函数。参考Python调用C/C++的两种方法官方:扩展和嵌入Python解释器【知识分享】C++与Python联合编程(上)【知识分享】C++与Python联合编程(下)使用ctypes在Python中调用C++动态库Pythonctypes:在C和Python之间传送一维数组Pythonctypes:在C和Numpy之间传送多维数组
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2025-1-10 05:42 , Processed in 0.426752 second(s), 26 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表