如何实现 C/C++ 与 Python 的通信

 我来答
从空去听8
2017-12-18 · TA获得超过7440个赞
知道大有可为答主
回答量:6907
采纳率:93%
帮助的人:5589万
展开全部
引入Python可以带来更好的可调式性。且如果重负载应用使用C/C++则基本没有性能损失,并可以让工程师把更多精力放在算法优化获得性能优势上。
简单讲Python与C/C++的直接交互就是两种方向:C/C++写扩展模块给Python调用;将Python嵌入C/C++。题主说的是后者。而更方便方式是前者。因为内嵌方式决定了你整个交互部分开发完成之前没法做测试。而扩展模块方式则可以先行用Python快速开发出大部分功能,有需要性能优化的部分逐步优化到C/C++。是更加渐进式的过程。
直接用最基础的方法写扩展模块略有繁杂,适合对细节的控制。题主时间紧迫则可以考虑Cython,可以在较短时间里完成些任务。但更多高级功能的玩法则限制很多。
其他交互方式还有多种,性能就不是那么高了。比如fork()子进程,用管道通信。开独立进程走mmap()交互,甚至是本机或其他机器上走socket。
最后,C++做了很多底层抽象,使得其与其他编程语言的互调用方面麻烦的要死。比较典型的包括类继承,运算符重载,引用,其他还有太多。这些特性使得其他语言调用C++时各种恶心。这不仅仅是对Python,而是对所有语言都是如此。不信试试在C程序里调用一个C++运算符重载过的方法。所以,如非必要,尽量别用C++。用C简单方便的多,而任何用以支持大规模项目的架构用Python就是了。
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
司马刀剑
高粉答主

2017-09-26 · 每个回答都超有意思的
知道顶级答主
回答量:4.6万
采纳率:93%
帮助的人:7531万
展开全部
用C/C++对脚本语言的功能扩展是非常常见的事情,Python也不例外。除了SWIG,市面上还有若干用于Python扩展的工具包,比较知名的还有Boost.Python、SIP等,此外,Cython由于可以直接集成C/C++代码,并方便的生成Python模块,故也可以完成扩展Python的任务。

答主在这里选用SWIG的一个重要原因是,它不仅可以用于Python,也可以用于其他语言。如今SWIG已经支持C/C++的好基友Java,主流脚本语言Python、Perl、Ruby、PHP、JavaScript、tcl、Lua,还有Go、C#,以及R。SWIG是基于配置的,也就是说,原则上一套配置改变不同的编译方法就能适用各种语言(当然,这是理想情况了……)

SWIG的安装方便,有Windows的预编译包,解压即用,绿色健康。主流Linux通常集成swig的包,也可以下载源代码自己编译,SWIG非常小巧,通常安装不会出什么问题。

用SWIG扩展Python,你需要有一个待扩展的C/C++库。这个库有可能是你自己写的,也有可能是某个项目提供的。这里举一个不浮夸的例子:希望在Python中用到SSE4指令集的CRC32指令。

首先打开指令集的文档
可以看到有6个函数。分析6个函数的原型,其参数和返回值都是简单的整数。于是书写SWIG的配置文件(为了简化起见,未包含2个64位函数):

/* File: mymodule.i */
%module mymodule

%{
#include "nmmintrin.h"
%}

int _mm_popcnt_u32(unsigned int v);
unsigned int _mm_crc32_u8 (unsigned int crc, unsigned char v);
unsigned int _mm_crc32_u16(unsigned int crc, unsigned short v);
unsigned int _mm_crc32_u32(unsigned int crc, unsigned int v);

接下来使用SWIG将这个配置文件编译为所谓Python Module Wrapper

swig -python mymodule.i

得到一个 mymodule_wrap.c和一个mymodule.py。把它编译为Python扩展:

Windows:
cl /LD mymodule_wrap.c /o _mymodule.pyd -IC:\Python27\include C:\Python27\libs\python27.lib

Linux:
gcc -fPIC -shared mymodule_wrap.c -o _mymodule.so -I/usr/include/python2.7/ -lpython2.7

注意输出文件名前面要加一个下划线。
现在可以立即在Python下使用这个module了:

>>> import mymodule
>>> mymodule._mm_popcnt_u32(10)
2

回顾这个配置文件分为3个部分:

定义module名称mymodule,通常,module名称要和文件名保持一致。
%{ %} 包裹的部分是C语言的代码,这段代码会原封不动的复制到mymodule_wrap.c
欲导出的函数签名列表。直接从头文件里复制过来即可。

还记得本文第2节的那个great_function吗?有了SWIG,事情就会变得如此简单:
/* great_module.i */
%module great_module
%{
int great_function(int a) {
return a + 1;
}
%}
int great_function(int a);

换句话说,SWIG自动完成了诸如Python类型转换、module初始化、导出代码表生成的诸多工作。

对于C++,SWIG也可以应对。例如以下代码有C++类的定义:
//great_class.h
#ifndef GREAT_CLASS
#define GREAT_CLASS
class Great {
private:
int s;
public:
void setWall (int _s) {s = _s;};
int getWall () {return s;};
};
#endif // GREAT_CLASS

对应的SWIG配置文件
/* great_class.i */
%module great_class
%{
#include "great_class.h"
%}
%include "great_class.h"

这里不再重新敲一遍class的定义了,直接使用SWIG的%include指令

SWIG编译时要加-c++这个选项,生成的扩展名为cxx
swig -c++ -python great_class.i

Windows下编译:
cl /LD great_class_wrap.cxx /o _great_class.pyd -IC:\Python27\include C:\Python27\libs\python27.lib

Linux,使用C++的编译器
g++ -fPIC -shared great_class_wrap.cxx -o _great_class.so -I/usr/include/python2.7/ -lpython2.7

在Python交互模式下测试:
>>> import great_class
>>> c = great_class.Great()
>>> c.setWall(5)
>>> c.getWall()
5

也就是说C++的class会直接映射到Python class

SWIG非常强大,对于Python接口而言,简单类型,甚至指针,都无需人工干涉即可自动转换,而复杂类型,尤其是自定义类型,SWIG提供了typemap供转换。而一旦使用了typemap,配置文件将不再在各个语言当中通用。
本回答被提问者采纳
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
收起 1条折叠回答
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式