混合编程—C++程序中python脚本的嵌入方法(理论部分)

一、C++与Python高级编程语言简概

(一)C++

        C++是一种被广泛使用的计算机程序设计语言。它是一种通用程序设计语言,支持多重编程范式,例如过程化程序设计(Procedural programming)、面向对象程序设计(object-oriented programming)泛型程序设计(generic programming)和函数式程序设计(Functional programming)等。作为广泛被使用的工业语言,C++存在多个流行的成熟实现:GCC、基于LLVM的Clang以及Visual C++等。这些实现同时也是成熟的C语言实现,但对C语言的支持程度不一。大多数流行的实现包含了编译器和C++部分标准库的实现。编译器直接提供核心语言规则的实现,而库提供ISO C++标准库的实现[4]。

         基于C++的面向对象程序设计的基本思想及主要特点为:抽象封装继承多态。C++程序的开发通常要经过编辑编译链接运行调试。其中,链接是将多个目标文件以及所需的库文件链接成最终的可执行文件(executable file,exe)的过程,包括合并段、调整段偏移、汇总所有符号以及完成所有符号的重定位/*6*/。具体流程如下所示:

图源:C++语言程序设计 / 郑莉,董渊编著.—5版.—北京:清华大学出版社

C++的适用时机/*4*//*1*/:

        Ⅰ C++适合构造程序中需求稳定的部分,需求变化较大的部分可使用脚本语言;

        Ⅱ 程序需尽量发挥硬件的最高性能,且性能瓶颈在于CPU和内存;

        Ⅲ 程序需频繁地与操作系统或硬件沟通;

        Ⅳ 程序必须使用C++框架/库,如大部分游戏引擎(如Unreal/Source)及中间件(如Havok/FMOD),虽然有些C++库提供其他语言的绑定,但通常原生的API性能最好、最新;

        Ⅴ 项目中某个目标平台只提供C++编译器的支持。         

        按应用领域来说,C++适用于开发服务器软件、桌面应用、游戏、实时系统、高性能计算、嵌入式系统等。

C++性能优于其他语言的原因/*4*/:

        Ⅰ C/C++直接以静态形式把源程序编译为目标平台的机器码;

        Ⅱ 一般而言,C/C++程序在编译及链接时可进行的优化最丰富,启动时的速度最快,运行时的额外内存开销最少,而C/C++相对于动态脚本语言(如Python)减少了运行时的动态类型检测;

        Ⅲ C/C++的运行行为是确定的,且不会有额外行为,也不会有如垃圾收集/*12*/而造成的不确定性延迟,再者,C/C++的数据结构在内存中的布局也是确定的;

        Ⅳ C++的一些功能会使程序性能优于C,其中以内联和模板最为突出。再者,C/C++能直接映射机器码,之间没有另一层中间语言,因此可以做底层优化。

        总而言之,C++许多的性能优点也会带来部分代价,如较长的编译/链接时间、容易出错等导致开发时间和成本增加。

(二)Python

        Python,是一种广泛使用的解释型、高级和通用的编程语言(脚本语言)。Python支持多种编程范型,包括结构化、过程式、反射式、面向对象和函数式编程。它拥有动态类型系统和垃圾回收(引用计数和环检测相结合)功能,能够自动管理内存使用,并且其本身拥有一个巨大而广泛的标准库以及大量的第三方库。Python的设计哲学,强调代码的可读性和简洁的语法,尤其是使用空格缩进来划分代码块。相比于C/C++,Python能让开发者使用更少的代码表达想法[5]。

Python的主要特点/*11*/:

        Ⅰ 跨平台:Python支持Windows、Linux和MAC os等主流操作系统;

        Ⅱ 可移植:代码通常不需要多少改动就能移植到别的平台上使用;

        Ⅲ 可扩展:Python语言本身由C语言编写而成的,既可以在Python中嵌入C语言以提高代码的运行速度和效率,也可以使用C语言重写Python的任何模块;

        Ⅳ 交互式:Python提供很好的人机交互界面,如IDLE和IPython。可以从终端输入执行代码并获得结果,互动的测试和调试代码片段;

        Ⅴ 解释型:Python语言在执行过程中由解释器逐行分析翻译,逐行运行并输出结果;

        Ⅵ 面向对象:Python语言具备所有面向对象特性和功能,支持基于类的程序开发;

        Ⅶ 动态语言:在运行时可以改变其结构。例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其它结构上的变化。

        值得注意的是,Python遵循GPL开源协议,Python编写的源代码通常是不加密的,即发布Python程序,实际上就是发布源代码。对于代码封闭而言,编译型语言(如C++,非ISO)只需发布可执行文件即可,而解释型语言(如Python)则必须发布源码,但是为了增加反编译的门槛和难度,可以使用类似py2exe工具将python源码转换成一个类似于exe的可执行文件形式。

Python的常见应用方向/*11*/:

        常规软件开发、科学计算、自动化运维、云计算、WEB开发、网络爬虫、数据分析、人工智能。

二、基础概念        

        回调函数/*8*//*9*/:在计算机程序设计中,回调函数,简称回调(Callback),是指通过参数将函数传递到其他代码的,某一块可执行代码的引用。回调的形式因程序设计语言有差别,如C++通过将函数指针作为参数传递给其他函数。使用回调的例子有QT中信号槽机制等。

        封装:封装是面向对象方法的一个重要原则,就是把对象的属性和服务结合成一个独立的系统单位(降低耦合),并尽可能隐蔽对象的内部细节。对于“信息隐蔽”,我们可以封装成类,只保留有限的对外接口使之与外部发生联系,从而对外形成一个边界,尽可能屏蔽对象的内部细节。

        脚本程序(Script):使用脚本语言所写的程序。脚本语言是为了缩短传统的“编写、编译、链接、运行”过程而创建的计算机编程语言。早期的脚本语言经常被称为批处理语言或作业控制语言。大多数脚本语言的共性是:良好的快速开发,有效率的执行、解释而非编译执行、和其它语言编写的程序组件之间通信功能强大,但是脚本缺少优化程序以提速或者降低内存的伸缩性。脚本通常以文本(如ASCII)保存,只在被调用时进行解释。

        extern(c++关键字)/*10*/:

        ①修饰全局变量:在声明全局变量的时候使用extern修饰变量,表明该变量定义于其他翻译单元。②修饰全局常量:表明该全局常量拥有外部链接(可以被其他翻译单元发现),否则全局常量默认是只有内部链接,即不可被其他翻译单元发现。③修饰局部变量:表明该局部变量在其他翻译单元中被定义,需要在链接的时候去解析。④修饰一个字符串:形如extern “C” 之类的用法表明后接的代码块(或者后接的声明)使用C语言调用惯例。⑤修饰一个模板:表明该模板已经在其他翻译单元实例化,不需要在这里实例化。

        (注:ISO C和ISO C++从未明确要求源程序被编译,而仅要求翻译,因此C和C++并不是所谓的完全编译型语言。技术上,实现C和C++程序的单位是翻译单元(translation unit),但是C/C++在传统上多以编译器实现[4]。)

/**/ 程序开发基本术语[6]

        源程序:用源语言编写的、有待翻译的程序。源语言可以是汇编语言,也可以是高级程序设计语言,用它们写出的程序都是源程序;

        目标程序:是源程序通过翻译加工以后所生成的程序。目标程序可以用机器语言表示,也可以用汇编语言或其它中间语言表示;

        翻译程序:是指用来把源程序翻译为目标程序的程序。对于翻译程序来说,源程序是它的输入,而目标程序则是其输出。翻译程序分为汇编程序编译程序以及解释程序三种类型,①汇编程序的任务是把用汇编语言写成的源程序翻译成机器语言形式的目标程序;②编译程序是指高级程序设计语言所写的源程序经翻译程序一次性加工生成目标程序(机器码)的过程;③解释程序同样是将高级语言源程序翻译为机器指令的过程。但不同于编译程序的是,它是边翻译边执行的,即输入一句,翻译一句,执行一句,直至将整个源程序翻译并执行完毕。

        编译型语言与解释型语言的区别/*3*/:        

        编译型语言(如C++等,非ISO),其需要针对不同操作系统进行编译以生成相应的底层机器码、若修改源文件则需要重新编译再执行。优点为运行速度快,缺点为繁琐、调试额外耗时和跨平台性较差;解释型语言(如Python等),其基于解释器动态将源代码边解释为机器码,边执行机器命令。优点为跨平台性好、调试较为迅速,缺点为依赖解释器、运行效率较低。

三、混合编程(C++/python)基本知识与封装规范[1][2]

(一)Python扩展(Extending Python)

        目的:附加C函数库来扩展Python的功能。

        应用程序主程序:Python解释器

        流程:首先,将数据值从Python类型转换为C类型。然后,使用转换后的值对C例程执行函数调用。最后,将调用返回的结果数据值从C类型转换为Python类型。

(二)Python嵌入(Embedding Python)

        目的:嵌入Python丰富C/C++应用程序,通常嵌入功能利用Python编写更为简单、逻辑清晰且独特可定制。

        应用程序主程序:C++编译器(需要的时候动态调用Python解释器)

        流程:首先,将数据值从C类型转换为Python类型。然后,使用转换后的值对Python接口例程执行函数调用。最后,将调用返回的结果数据值从Python类型转换为C类型。

(三)C++和Python混合编程的优势与使用Python C API的注意事项[12]

        优势

        Ⅰ 主体系统使用C++实现,保持系统的高效;

        Ⅱ 控制部分使用Python,增加开发效率,Python的内存垃圾回收、丰富的类库都使C++开发者获益匪浅;

        Ⅲ Python脚本可以运行期重载,可以实现控制部分不停机热更新。

        使用Python C API的注意事项

        Ⅰ Python主要使用引用计数管理内存,调用Python C API时对于返回值返回的是借用的引用还是新的引用,需要根据文档仔细确认。否则,轻则出现内存泄漏,重则程序崩溃;

        Ⅱ Python中的数据结构与C++的有很大不同。Python常用的有tuple、list、dict,而C++常用的是vector、list、map,并且C++是强类型的。当C++与Python进行交互时,C++层希望操作Python数据结构就像操作C++ STL一样方便,而在Python脚本层,又希望C++传入的参数或返回值都是原生的Python数据;

        Ⅲ C++中常用指针传递对象,当嵌入Python时,需要把C++对象传递到Python中。

不同文件扩展名文件认识

.h                --- C++头文件

.cpp            --- C++源程序文件

.obj             --- Windows系统下的C++源程序经过编译后生成的目标文件(UNIX系统为.o)

.exe            --- Windows系统下的可执行程序(多个目标文件与库/资源文件的链接生成)

.dll   /*13*/  --- Windows系统下的动态链接库(Dynamic Link Library),.dll文件有如下用途:

                        ①代码共享:.dll文件中一些功能或服务的实现代码,多个应用程序可以共享同一个.dll文件,避免重复编写相同的代码;

                        ②动态链接:.dll文件是在运行时动态链接到应用程序中的;

                        ③扩展性:通过使用.dll文件,可以方便地向现有的应用程序添加新的功能或模块,而不需要修改或重新编译整个应用程序。只需将新的.dll文件提供给应用程序,然后在运行时加载和使用新的功能;

                        ④动态更新:由于.dll文件是独立于应用程序的,可以对.dll文件进行更新和升级,而不影响应用程序的正常运行。这使得软件的维护和升级变得更加灵活和方便。

.lib    /*14*/    --- Windows系统下的完全静态链接库(包含所有的导出声明和实现)或伴随.dll生成的动态.lib(动态.lib只包含一些函数索引信息,记录了.dll中那些函数的入口和位置)

.py              --- Python源程序文件

.pyd            --- 一般是C/C++编写的Python扩展模块,即Python的一个动态链接库(Linux 系统中一般为.so文件)

注意事项

       Ⅰ 完全静态.lib文件实际上就是任意个.obj文件的集合(任意个.obj文件链接生成一个完全静态.lib);

        Ⅱ .dll近似于.exe,只不过没有主函数(main)而不能单独执行。实际工程中,很多应用程序都并不是一个完整的单独可执行文件,它们被分割成一些单独的相对独立的动态链接库,只有在执行应用程序的时候,用到的.dll才会被调用。

参考资料:

官方文档

[1] Extending and Embedding the Python Interpreter — Python 3.9.17 documentation

[2] Python/C API Reference Manual — Python 3.9.17 documentation

[3] Welcome to Cython’s Documentation — Cython 3.0.7 documentation

Wikipedia

[4] https://zh.wikipedia.org/wiki/C%2B%2B(C++)

[5] https://zh.wikipedia.org/wiki/Python(Python)

参考书籍

[6] C++语言程序设计 / 郑莉,董渊编著.—5版.—北京:清华大学出版社,2020.11.

优秀博客及学习视频资源

[7] c++ 调用 python_哔哩哔哩_bilibili

[8] C++调用Python(混合编程)函数整理总结-CSDN博客

[9] Python与C/C++混合编程 - 知乎

[10] C++(Qt)与Python混合编程(一) - 知乎

[11] C++(Qt)与Python混合编程(二) - 知乎

[12] C++使用ffpython嵌入和扩展python-阿里云开发者社区

[13] Docs(C++调用Python脚本)

拓展资料

/*1*/ 站在巨人的肩膀上,C++开源库大全-阿里云开发者社区

/*2*/ github上总结的python资源列表【转】-阿里云开发者社区

/*3*/ 计算机基础------计算机语言分类(脚本语言引发的思考)-阿里云开发者社区

/*4*/ C++强大的背后-阿里云开发者社区

/*5*/ 你知道.c是如何变成.exe的吗 - 知乎

/*6*/ C/C++编译链接 - 知乎

/*7*/ Python PyInstaller 打包成 Win、Mac 应用程序(app / exe)-阿里云开发者社区

/*8*/ 回调函数详解-CSDN博客

/*9*/ https://zh.wikipedia.org/wiki/%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0(回调函数)

/*10*/ C++中的extern_c++ extern-CSDN博客

/*11*/ 1-Python介绍-阿里云开发者社区

/*12*/  C/C++中几种经典的垃圾回收算法_c 垃圾回收算法-CSDN博客

/*13*/ c++中什么叫dll文件,有什么用_c++推送数据dll文件-CSDN博客

/*14*/ 关于lib文件的介绍-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/315526.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CISSP 第1章:实现安全治理的原则和策略

作者:nothinghappend 链接:https://zhuanlan.zhihu.com/p/669881930 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 CIA CIA 三性: 机密性:和数据泄露有关。完整性…

odoo17 | 模型和基本字段

前言 在上一章的最后,我们能够创建一个Odoo模块。然而,在这一点上,它仍然是一个空壳,不允许我们这样做 存储任何数据。在我们的房地产模块中,我们希望存储与 数据库中的属性(名称、描述、价格、居住面积等…

【BIG_FG_CSDN】C++ 数组与指针 (个人向——学习笔记)

一维数组 在内存占用连续存储单元的相同类型数据序列的存储。 数组是静态存储器的块;在编译时确定大小后才能使用; 其声明格式如下: 元素类型 数组名[常量];元素类型:数组中元素的数据类型; 常量&#…

Python 自学(二) 之流程控制语句

目录 1. if ... elif ... else 语句 P62 1. if ... elif ... else 语句 P62 每个判断语句后面要加 :elif 的写法比较特别

【搜索引擎】elastic search核心概念

前言 本文不涉及ES的具体安装下载、操作、集群的内容,这部分内容会放在后面一篇文章中。本文只包含ES的核心理论,看完本文再去学ES的细节会事半功倍。 目录 1.由日志存储引出的问题 2.什么是ES? 3.ES的数据结构 4.ES的核心原理 5.联系作…

iOS问题记录 - iOS 17通过NSUserDefaults设置UserAgent无效(续)

文章目录 前言开发环境问题描述问题分析1. 准备源码2. 定位源码3. 对比源码4. 分析总结 解决方案补充内容1. UserAgent的组成2. UserAgent的设置优先级 最后 前言 在上篇文章中对该问题做了一些判断和猜测,并给出了解决方案。不过,美中不足的是没有进一…

Peter算法小课堂—动态规划

Peter推荐算法书:《算法导论》 图示: 目录 钢条切割 打字怪人 钢条切割 算法导论(第四版)第十四章第一节:钢条切割 题目描述: 给定一根长度为 n 英寸的钢条和一个价格表 ,其中 i1,2,…,n …

LaTeX写论文,公式后段落取消缩进方法:\noindent

在论文的段落中,需要插入一个公式,按道理公式后应该紧接着是段落的文本内容,但如果直接写的话,编译得到的PDF中呈现出来的却是开头缩进的样子 如果需要取消公式后面的段落缩进,可以使用命令 \noindent 该命令的作用…

十年磨一剑,花为缘享奢app打造行业的又一颠覆性创新

随着国内生活质量的提高,人们对于奢侈品的消费需求也在不断增长。消费者对于高品质、高价值的商品和服务的需求日益增长。2022年我国内地消费者奢侈品市场规模约为4700亿元,预计2023年我国内地消费者奢侈品消费预计将达到5500亿元,呈现出强劲…

华为鸿蒙运行Hello World

前言: 从11月中旬开始通过B站帝心接触鸿蒙,至今一个半月左右不到,从小白到入坑,再到看官网案例,分析案例,了解技术点,还需要理清思路,再写博客,在决定写 <Har…

MessageBox:连接HubSpot和微信的桥梁

在当今充满挑战的商业环境中,成功的企业需要高效整合不同的平台和系统,以提升客户关系管理的水平。在这一复杂的任务中,MessageBox凭借其卓越的功能和灵活性,不仅成为连接HubSpot和微信的桥梁,更是实现精细化客户关系的…

【Spark精讲】SparkSQL的RBO与CBO

Spark SQL核心:Catalyst Spark SQL的核心是Catalyst查询编译器,它将用户程序中的SQL/Dataset/DataFrame经过一系列操作,最终转化为Spark系统中执行的RDD。 Catalyst组成部分 Parser :用Antlr将SQL/Dataset/DataFrame转化成一棵未经解析的树…