C/C++调用Python程序代码实现混合编程笔记教程

news2025/4/13 5:55:36

0、引言

        Python‌在基础开发、数据科学、人工智能、Web框架开发等领域具有广泛的支持工具和开发教程,极大的缩短了产品原型开发周期、降低了开发难度。

        有许多的功能,通过C/C++实现,非常的复杂并且不方便,但是Python可能就是几行代码就搞定了。

        为了避免处处重复造轮子,又希望在原先的C/C++通用轻松简单的实现一些功能,因此探索在C/C++中如何嵌入调用Python的API及应用程序非常有必要。

1、开发环境搭建

①、Python

        本文以当前最新的Python 3.13.3版本为例进行讲解,本教程的Python下载地址如下:

Download Python | Python.orghttps://www.python.org/downloads/

        由于Python的版本也一直在更新,如果找查阅到本教程时,最新版本已不是Python3.13.3,可以滑动找到Python的历史版本进行安装。

        并在安装完成后,建议通过终端命令行查询一下具体的版本信息:python --version

②、MinGW

        简单来说,MinGW是一个编译器,提供了gcc和g++编译工具,可以对C/C++程序代码编译调试。

        在之前的很多博客笔记文章中已经对MinGW进行了非常多的讲解了,如果对MinGW编译器有疑惑的,可以通过博主的如下笔记链接,搭建安装MinGW开发环境。

MinGW编译器任意版本使用配置经验教程-CSDN博客https://blog.csdn.net/weixin_49337111/article/details/140274770?spm=1001.2014.3001.5502

③、CMake

        CMake(Cross-platform Make)是一款开源的跨平台构建系统生成工具,广泛应用于C、C++、Fortran等编程语言的项目构建中。

        在VScode,可以直接安装VScode插件构建工具,即可实现在VScode中使用CMake。

        提醒:在一些环境中,可能无法正常使用CMake插件,需要下载最新的CMake程序软件才能辅助使用。

2、工程代码配置

        在上面的开发环境搭建好之后,当在程序代码中加入Python相关的头文件时,大概率会出现如下情况,找不到相关头文件,并且编译会直接报错。

        上面这个情况也就是说明,并没有和Python建立联系,需要我们自己将Python的路径加入到工程代码的配置中。

        通过python --path命令,即可找到python的实际安装路径

        python实际的文件所在路径,include包含了C/C++中需要使用的xxx.h头文件。

        在libs中提供的是_tkinter.lib、python3.lib、python313.lib

        如果在MinGW中不能直接使用xxx.lib库文件,要进行文件格式转换,对于没有接触过了开发者,可能处理起来较为麻烦,如有需要,可以访问博主在下面这篇文章中提到的方法。

Windows中xxx.dll动态链接库文件转xxx.a静态库文件-CSDN博客https://blog.csdn.net/weixin_49337111/article/details/147171368?sharetype=blogdetail&sharerId=147171368&sharerefer=PC&sharesource=weixin_49337111&spm=1011.2480.3001.8118

        如果觉得不方便,可以采取直接在Visual Studio程序中包含xxx.lib文件,同样可以实现C/C++中嵌入Python程序进行开发。

        在完成上面的操作后,即可创建C/C++工程了,然后配置CMakeLists.txt文件。博主在一系列试错了,最终成功运行的文件如下:

        CMakeLists.txt

cmake_minimum_required(VERSION 3.10.0)
project(convert VERSION 0.1.0 LANGUAGES C CXX)

# 设置Python路径
set(PYTHON_INCLUDE_DIR "C:/Users/Administrator/AppData/Local/Programs/Python/Python313/include")
set(PYTHON_LIBRARY "C:/Users/Administrator/AppData/Local/Programs/Python/Python313/libs/python313.lib")

# 添加可执行文件
add_executable(convert main.cpp)

# 包含Python头文件目录
target_include_directories(convert PRIVATE ${PYTHON_INCLUDE_DIR})

# 链接Python库
target_link_libraries(convert PRIVATE ${PYTHON_LIBRARY})

# 在Windows上需要定义PYTHON_LIBRARY宏
if(WIN32)
    target_compile_definitions(convert PRIVATE PYTHON_LIBRARY)
endif()

        提醒:如果在Windows环境中,发现存在MSVC会和当前MinGW编译器混用,建议直接换更新版本的MinGW,经过反复试错,最终得出来的正确解决办法,惨痛的教训!!!

        在编译正常运行后,说明环境搭建完毕,工程配置正常,可以开始C/C++中正常调用Python进行开发了。

3、C/C++中调用Python

        对于在C/C++中如何使用Python的API接口,Python官方已经出来非常详细的教程,有需要的博客朋友可以访问如下链接对该教程参考学习。

        Python的C/C++外部扩展官方教程:

1. Embedding Python in Another Application — Python 3.13.3 documentationhttps://docs.python.org/3.13/extending/embedding.html

①、常用API接口

(1)初始化 Python 解释器

//用于初始化 Python 解释器,它会设置 Python 运行所需的环境,加载内置模块等。
void Py_Initialize(void);

(2)终止 Python 解释器

//程序结束时,要调用此函数来终止解释器,释放相关资源。
void Py_Finalize(void);

(3)命令行参数处理

//将 C/C++ 程序的命令行参数传递给 Python 解释器。
void PySys_SetArgv(int argc, char **argv);

(4)执行Python简单语句

//使用此函数接口可以在 C/C++ 代码中执行简单的 Python 语句。
int PyRun_SimpleString(const char *command);

(5)执行 Python 文件

//使用此函数接口,可以在C/C++代码中间接执行 Python 文件
int PyRun_SimpleFile(FILE *fp, const char *filename);

(6)导入 Python 模块

//此函数接口,可以实现导入 Python 模块。
PyObject* PyImport_ImportModule(const char *name);

(7)调用 Python 函数

//用于在 C/C++ 中调用 Python 的可调用对象(函数、方法、类等)。
PyObject* PyObject_CallObject(PyObject *callable, PyObject *args);

②、程序实例

(1)Python语句执行

//    C/C++测试 HTTP 请求和 HTML 解析功能效果如下:
#include <Python.h>
#include <iostream>
#include <string>
#include <stdexcept>

class PythonHttpParser {
public:
    PythonHttpParser() {
        Py_Initialize();
        // 确保 requests 和 bs4 可用
        PyRun_SimpleString(
            "import sys\n"
            "try:\n"
            "    import requests\n"
            "    from bs4 import BeautifulSoup\n"
            "except ImportError as e:\n"
            "    print(f'Error: {e}')\n"
            "    sys.exit(1)\n"
        );
    }
    
    ~PythonHttpParser() {
        Py_Finalize();
    }
    
    std::string fetch_title(const std::string& url) {
        PyObject *pFunc, *pArgs, *pResult;
        
        // 获取 main 模块
        PyObject* main_module = PyImport_AddModule("__main__");
        PyObject* global_dict = PyModule_GetDict(main_module);
        
        // 准备 Python 代码
        const char* code = 
            "def get_page_title(url):\n"
            "    try:\n"
            "        response = requests.get(url)\n"
            "        soup = BeautifulSoup(response.text, 'html.parser')\n"
            "        return soup.title.string if soup.title else 'No title found'\n"
            "    except Exception as e:\n"
            "        return f'Error: {str(e)}'\n";
        
        PyRun_SimpleString(code);
        
        // 获取函数
        pFunc = PyDict_GetItemString(global_dict, "get_page_title");
        if (!pFunc || !PyCallable_Check(pFunc)) {
            throw std::runtime_error("Failed to get Python function");
        }
        
        // 准备参数
        pArgs = PyTuple_New(1);
        PyTuple_SetItem(pArgs, 0, PyUnicode_FromString(url.c_str()));
        
        // 调用函数
        pResult = PyObject_CallObject(pFunc, pArgs);
        if (!pResult) {
            PyErr_Print();
            throw std::runtime_error("Python function call failed");
        }
        
        // 获取结果
        std::string result = PyUnicode_AsUTF8(pResult);
        
        // 清理
        Py_DECREF(pArgs);
        Py_DECREF(pResult);
        
        return result;
    }
};

int main() {
    try {
        PythonHttpParser parser;
        std::string title = parser.fetch_title("https://en.wikipedia.org/wiki/Main_Page");
        std::cout << "Page title: " << title << std::endl;
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }
    return 0;
}

        C/C++测试 HTTP 请求和 HTML 解析功能效果如下:

(2)Python代码文件调用

#include <Python.h>
#include <cstdio>
#include <cstdlib>

int main(int argc, char* argv[]) {
    // 初始化 Python 解释器
    Py_Initialize();

    // 创建一个 wchar_t** 数组来存储转换后的命令行参数
    wchar_t** wargv = (wchar_t**)malloc(argc * sizeof(wchar_t*));
    if (!wargv) {
        perror("Failed to allocate memory");
        Py_Finalize();
        return 1;
    }

    for (int i = 0; i < argc; ++i) {
        wargv[i] = Py_DecodeLocale(argv[i], nullptr);
        if (!wargv[i]) {
            perror("Failed to decode argument");
            for (int j = 0; j < i; ++j) {
                PyMem_RawFree(wargv[j]);
            }
            free(wargv);
            Py_Finalize();
            return 1;
        }
    }

    // 将转换后的参数传递给 Python
    PySys_SetArgv(argc, wargv);

    // 指定要运行的 Python 脚本文件名
    const char* script_file = "../script.py";

    // 打开 Python 脚本文件
    FILE* fp = fopen(script_file, "r");
    if (!fp) {
        perror("Failed to open file");
        for (int i = 0; i < argc; ++i) {
            PyMem_RawFree(wargv[i]);
        }
        free(wargv);
        Py_Finalize();
        return 1;
    }

    // 运行 Python 脚本
    int result = PyRun_SimpleFile(fp, script_file);
    fclose(fp);

    // 释放分配的内存
    for (int i = 0; i < argc; ++i) {
        PyMem_RawFree(wargv[i]);
    }
    free(wargv);

    // 终止 Python 解释器
    Py_Finalize();

    return result;
}

        script.py

import sys

# 打印接收到的命令行参数
print(f"Received arguments: {sys.argv}")

# 检查是否包含 --help 参数
if "--help" in sys.argv:
    print("Usage: script.py [--input <file>] [--verbose]")
    

        程序执行结果:

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LeetCode hot 100—子集

题目 给你一个整数数组 nums &#xff0c;数组中的元素 互不相同 。返回该数组所有可能的子集&#xff08;幂集&#xff09;。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 示例 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[],[1],[2…

Linux网络编程——数据链路层详解,以太网、MAC地址、MTU、ARP、DNS、NAT、代理服务器......

目录 一、前言 二、以太网 二、以太网帧格式 三、 MAC地址 四、MTU 1、数据链路层的数据分片 2、MTU对UDP协议的影响 3、MTU对TCP协议的影响 五、ARP协议 1、什么是ARP 2、ARP的作用 3、ARP协议的工作流程 4、ARP缓存表 5、ARP请求报文 6、中间人 六、DNS&…

基于springboot+vue的秦皇岛旅游景点管理系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;Maven3.3.9 系统展示 用户登录 旅游路…

Linux网络编程——TCP通信的四次挥手

一、前言 上篇文章讲到了TCP通信建立连接的“三次握手”的一些细节&#xff0c;本文再对TCP通信断开连接的“四次挥手”的过程做一些分析了解。 二、TCP断开连接的“四次挥手” 我们知道TCP在建立连接的时需要“三次握手”&#xff0c;三次握手完后就可以进行通信了。而在通…

计算机视觉算法实现——SAM实例分割:原理、实现与应用全景

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​​​ ​​​​​​​​​ ​​ 1. 实例分割领域概述 实例分割(Instance Segmentation)是计算机视觉领域最具挑战性的任务之一&#xff0c…

基于SpringBoot的宠物健康咨询系统(源码+数据库+万字文档)

502基于SpringBoot的宠物健康咨询系统&#xff0c;系统包含三种角色&#xff1a;管理员、用户&#xff0c;顾问主要功能如下。 【用户功能】 1. 首页&#xff1a;查看系统主要信息和最新动态。 2. 公告&#xff1a;浏览系统发布的公告信息。 3. 顾问&#xff1a;浏览可提供咨询…

vue2 el-element中el-select选中值,数据已经改变但选择框中不显示值,需要其他输入框输入值才显示这个选择框才会显示刚才选中的值

项目场景&#xff1a; <el-table-column label"税率" prop"TaxRate" width"180" align"center" show-overflow-tooltip><template slot-scope"{row, $index}"><el-form-item :prop"InquiryItemList. …

CCF CSP 第35次(2024.09)(2_字符串变换_C++)(哈希表+getline)

CCF CSP 第35次&#xff08;2024.09&#xff09;&#xff08;2_字符串变换_C&#xff09; 解题思路&#xff1a;思路一&#xff08;哈希表getline&#xff09;&#xff1a; 代码实现代码实现&#xff08;思路一&#xff08;哈希表getline&#xff09;&#xff09;&#xff1a; …

Docker--利用dockerfile搭建mysql主从集群和redis集群

Docker镜像制作的命令 链接 Docker 镜像制作的注意事项 链接 搭建mysql主从集群 mysql主从同步的原理 MySQL主从同步&#xff08;Replication&#xff09;是一种实现数据冗余和高可用性的技术&#xff0c;通过将主数据库&#xff08;Master&#xff09;的变更操作同步到一个…

蓝桥杯嵌入式考前模块总结

一.RTC 使用RTC直接再cubeMX中配置启动时钟和日历 如第六届省赛 想要让RTC的秒每隔一秒递增1需要在时钟树界面观察RTC的主频 由于RTC时钟主频为32KHZ将异步预分频计数器的值设为31&#xff0c;将同步预分频计数器的值设为999这样就可以将RTC的时钟信号分频为1HZ达到1秒自增的…

关于举办“2025年第五届全国大学生技术创新创业大赛“的通知

赛事含金量 大赛获奖即可有机会为你的大学里的“创新创业”加分&#xff01;这是每个大学要求必须修满的学分&#xff01; 中国“互联网&#xff0b;”大学生创新创业大赛磨刀赛&#xff01;“挑战杯”中国大学生创业计划大赛必参赛&#xff01; 国赛获奖&#xff0c;“互联…

Ingress蓝绿发布

Ingress蓝绿发布 Ingress常用注解说明yaml资源清单绿色版本yml资源清单蓝色版本yaml资源清单 主Ingress金丝雀Ingress基于客户端请求头的流量切分结果验证 基于客户端来源IP的流量切分结果验证 基于服务权重的流量切分结果验证 基于IP来源区域来切分IP---方案未验证基于User-Ag…

基于AOP+Log4Net+AutoFac日志框架

1.项目概述 这是一个基于 C# 的 WPF 项目 WpfApp12log4net&#xff0c;它综合运用了依赖注入、日志记录和接口实现等多种技术&#xff0c;同时使用了 Autofac、Castle.Core 和 log4net 等第三方库。 2.配置log4net 新建一个Log4Net.config&#xff0c;配置需要记录的日志信息…

python推箱子游戏

,--^----------,--------,-----,-------^--,-------- 作者 yty---------------------------^----------_,-------, _________________________XXXXXX XXXXXX XXXXXX ______(XXXXXXXXXXXX(________(------ 0 [[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [1,0,0,0,0,0,0,0,0,0,0,0,…

华为hcie证书的有效期怎么判断?

在ICT行业&#xff0c;华为HCIE证书堪称含金量极高的“敲门砖”&#xff0c;拥有它往往意味着在职场上更上一层楼。然而&#xff0c;很多人在辛苦考取HCIE证书后&#xff0c;却对其有效期相关事宜一知半解。今天&#xff0c;咱们就来好好唠唠华为HCIE证书的有效期怎么判断这个关…

PowerBI 条形图显示数值和百分比

数据表: 三个度量值 销售额 SUM(销量表[销售量])//注意, 因为Y轴显示的产品&#xff0c;会被筛选&#xff0c;所以用ALLSELECTED来获取当前筛选条件下&#xff0c;Y轴显示的产品 百分比 FORMAT(DIVIDE([销售额],CALCULATE([销售额],ALLSELECTED(销量表[产品编码]))),"0…

基于YOLOv8的火车轨道检测识别系统:技术实现与应用前景

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​​​ ​​​​​​​​​ ​​ 1. 引言&#xff1a;火车轨道检测领域概述 铁路运输作为国民经济的大动脉&#xff0c;其安全运行至关重要…

css使用mix-blend-mode的值difference实现内容和父节点反色

1. 使用场景 往往开发过程中&#xff0c;经常遇到产品说你这个背景图和文字颜色太接近了&#xff0c;能不能适配下背景图&#xff0c;让用户能够看清具体内容是啥。 这么说吧&#xff0c;这种需求场景非常合理&#xff0c;因为你做开发就是要给用户一个交代&#xff0c;给他们…

Pytest多环境切换实战:测试框架配置的最佳实践!

你是否也遇到过这种情况&#xff1a;本地测试通过&#xff0c;一到测试环境就翻车&#xff1f;环境变量错乱、接口地址混乱、数据源配置丢失……这些「环境切换」问题简直像定时炸弹&#xff0c;随时引爆你的测试流程&#xff01; 测试人员每天都跟不同的环境打交道&#xff0…

单细胞多组学及空间组学数据分析与应用

一、引言 生命科学研究正处于快速发展的阶段&#xff0c;随着技术的不断革新&#xff0c;对生物系统的理解也在逐步深入到单细胞和空间层面。单细胞多组学及空间组学技术应运而生&#xff0c;它们突破了传统研究手段在细胞异质性和空间结构解析上的局限&#xff0c;为我们打开…