Linux c 与 python的互操作

这篇具有很好参考价值的文章主要介绍了Linux c 与 python的互操作。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.最简单的调用方式:

int alc_FFT_of(const char *topic_fmt, int ch, cJSON *result)
{
    //Py_Initialize();

    pthread_mutex_lock(&mqtt_mutex);
    // 调用 Python 函数
    PyRun_SimpleString("print('Hello, World!')");
    pthread_mutex_unlock(&mqtt_mutex);
    
    //Py_Finalize();
    return 0;
}

注意,上面的是最简单的单向执行代码。代码如果涉及多线程执行,可以使用全局mutex来进行同步。

2.数据传递

2.1 方法一,文本模式,通过字典对象:

//在Python解释器中获取脚本的主模块和全局字典:
PyObject *pModule = NULL;
PyObject *pDict = NULL;

pModule = PyImport_AddModule("__main__");
pDict = PyModule_GetDict(pModule);
//使用PyRun_String函数来执行Python代码,并传递参数给脚本。可以使用PyEval_GetGlobals()函数获取脚本执行的全局字典,在这个字典中你可以定义脚本中可用的变量或者函数。
PyObject *pResult = NULL;
const char *script = "print('Hello, ' + name)";

PyObject *pGlobals = PyEval_GetGlobals();
PyDict_SetItemString(pGlobals, "name", PyUnicode_FromString("John"));

pResult = PyRun_String(script, Py_file_input, pDict, pGlobals);
//在上述例子中,我们将name变量传递给Python脚本。你可以根据需要传递更多的参数,只需在全局字典中设置相应的变量即可。

//在获取结果之后,你可以根据需要处理脚本的输出或返回值(如果有的话):
if (pResult != NULL) {
    if (PyErr_Occurred()) {
        PyErr_Print();
    }
    Py_DECREF(pResult);
}
//最后,不要忘记在完成后清理和关闭Python解释器:
Py_Finalize();

 2.2 方法二,涉及大量二进制数据的传递:

Python的C API提供了将二进制数据传递给Python脚本的方式。你可以使用PyBytes_FromStringAndSize函数将C/C++中的二进制数据转换为Python的bytes对象,并将其传递给脚本。

事实上,这个参数最终仍然是通过Dictionary过去的

//2进制模式传递参数的python-c互操作示例:

#include <Python.h>

int main(int argc, char *argv[]) {
    Py_Initialize();
    
    // 创建二进制数据
    unsigned char binaryData[] = {0x01, 0x02, 0x03, 0x04, 0x05};
    size_t binarySize = sizeof(binaryData);
    
    // 将二进制数据转换为Python的bytes对象
    PyObject *pBytes = PyBytes_FromStringAndSize((const char *)binaryData, binarySize);
    
    // 将bytes对象传递给脚本
    PyObject *pModule = PyImport_AddModule("__main__");
    PyObject *pDict = PyModule_GetDict(pModule);
    PyDict_SetItemString(pDict, "binary_data", pBytes);
    
    // 执行脚本
    const char *script = "print(binary_data)";
    PyRun_String(script, Py_file_input, pDict, pDict);
    
    // 释放Python对象
    Py_XDECREF(pBytes);
    
    Py_Finalize();
    return 0;
}

3. 涉及data in => python => data out的情形,建议的调用模式

3.1  C一侧的代码示例

#define PY_RUN_STANDALONE
int all_python_funcXXXXX_of(cJSON *src, cJSON *FFT, const char *py_sh_filename)
{
    if((src == NULL) ||(FFT==NULL)) return -1;
#ifdef PY_RUN_STANDALONE
    Py_Initialize();
    pModule = PyImport_AddModule("__main__");
    pDict = PyModule_GetDict(pModule);    
#endif
    // 调用 Python 函数
    const char *cstr = cJSON_Print(src);
    PyObject *pObject = PyUnicode_FromString(cstr);
    PyDict_SetItemString(pDict, "paramIn", pObject); //参数,传入paramIn字符串,直接在python可见
     // 调用 Python 函数
    FILE *file = fopen(py_sh_filename, "r");
    if(file==NULL)
    {
         //deal error....
         cJSON_AddItemToObject(FFT, "binData", cJSON_CreateString(""));
    }
    else
    {
        PyRun_File(file, py_sh_filename, Py_file_input, pDict, pDict);
        PyObject *pKeys = PyDict_GetItemString(pDict, "resultOut"); //python的传出参数,也是字符串模式
        if(pKeys == NULL)  
        {
            cJSON_AddItemToObject(FFT, "binData", cJSON_CreateString(""));
        }
        else
        {
            char *keyStr = PyUnicode_AsUTF8(pKeys); //无需手工析构
            cJSON *result = cJSON_Parse(keyStr);

            cJSON *elem = result->child;
            while (elem != NULL) {
                printf("result of python:%s\n", elem->string); fflush(stdout);
                cJSON_AddItemToObject(FFT, elem->string, cJSON_Duplicate(elem, 1));
                elem = elem->next;
            }
            cJSON_Delete(result);
        }
        //PyDict_Clear(pDict);    
        close(file);
    }
    free(cstr);
#ifdef PY_RUN_STANDALONE
    Py_Finalize();
#endif
    
    return 0;
}

3.2  Python脚本一侧的框架示例

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# paramsIn => resultOut json => json.
import json
import binascii
import numpy as np;
import sys

#print("python version: %s", sys.version);

#c input params = >paramIn
jsonStr = paramIn;
#jsonStr = '{"binData": "48656c6c6f20576f726c6421"}'

#to json obj
data = json.loads(jsonStr)

###########################################################################
# Stage 1: here input json has been transfered to variable: data

# get hex buff. got an item form json.
hex_data = data['binData']

# get byte array. 
byte_data = binascii.unhexlify(hex_data)
ba =  bytearray(byte_data);

#计算FFT
signal = ba
fft_result = np.fft.fft(signal)

# 从 FFT 结果中提取幅度谱
amplitude_spectrum = np.abs(fft_result)

# 将幅度谱长度的一半舍去
half_length = len(amplitude_spectrum) // 2
amplitude_spectrum = amplitude_spectrum[:half_length]

# to hex again.
# 将浮点数组转换为 4 字节浮点型编码的二进制数据
ba = amplitude_spectrum.astype(np.float32).tobytes()

hex_data = binascii.hexlify(ba).decode('utf-8')

# create json obj again.
data = {'binData': hex_data}

root = {
    'binData':hex_data,
    'fft_result_pt':len(signal),
    'fft_result_len': len(hex_data)
}

# Stage 2: here out json object has been established to object: root
###########################################################################

# json => final json_str_out
resultOut = json.dumps(root)

4. 循环调用、垃圾回收、异常捕获

如果仅仅是单次运行Python,上面的描述足够用。如果你需要周期性地调用Python代码。那么会有一些额外的问题需要考量,比如这个:

https://discuss.python.org/t/is-there-any-helpful-debug-tools-to-accelerate-c-python-debug/34449

因为不同的.py共用一个执行环境,它会导致名字污染,在你无意识地重定义了一个built_in  function 然后,很奇怪的事情就会出现。文章来源地址https://www.toymoban.com/news/detail-692113.html

4.1循环调用过程中的主动垃圾回收

//step 1.对最重要的两个外层交互用的Python对象添加引用计数
    Py_Initialize();
    pModule = PyImport_AddModule("__main__");
    pDict = PyModule_GetDict(pModule);    
    Py_INCREF(pModule);
    Py_INCREF(pDict);

//Step 2.退出时的反向操作
    Py_DECREF(pModule);
    Py_DECREF(pDict);
    Py_DECREF(pDict);    // 释放pDict对象的引用
    //ResetPyEnvironment();
    Py_DECREF(pModule);  // 释放pModule对象的引用
    Py_Finalize();

//Step3.主动在py脚本文件执行完毕后,调用py格式的垃圾回收脚本。
onst char *pyFileResetEnvironment = "./py/garbdge_collect.py";
void ResetPyEnvironment(void)
{
    InvokePythonFile(pyFileResetEnvironment);
}

4.2相关的垃圾主动回收.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import gc

#输出参数删除
resultOut = None
del resultOut
#输入参数删除
paramIn = None
del paramIn
gc.collect()

4.3 调试信息打印

        void *ret = PyRun_File(file, py_sh_filename, Py_file_input, pDict, pDict);
        if(ret ==NULL) 
        {
            //when exception occur, can print line number of bug related line.
            PyErr_Print(); 
            printf(".py invoke error %s\n", py_sh_filename);fflush(stdout);
            fclose(file);
            exit(0);
        }

附录A C与Python互操作需要的软件包

# python
yum install python3-devel

#互操作可能涉及到的cJSON
#需要下载cJSON-master源码:
cd /workerspace/sensor/src/data_dispatch/3rd/cJSON-master
make clean
make
make install
sudo ln -s /usr/local/lib/libcjson.so.1 /usr/lib/libcjson.so.1
sudo ldconfig 

#gcc
yum install gcc-c++ cmake openssl-devel -y

#也许你会用到mqtt
#mosquitto这个也要下载源码包,包含服务器,但是可以不运行。
make clean
make
make install
sudo ln -s /usr/local/lib/libmosquitto.so.1 /usr/lib/libmosquitto.so.1
sudo ldconfig 

#uuid.
yum install uuid-devel
yum install libuuid-devel

附录B 操控某个特定的python执行环境添加pip包的语法

#注意 -i --trusted-host的相对顺序,国外的服务器延迟太大,几乎无法访问
python3 -m pip install --timeout 200 --trusted-host mirrors.aliyun.com -i http://mirrors.aliyun.com/pypi/simple/ numpy

附录C  待执行的.python脚本的示例

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import json
import binascii
import numpy
import sys

print("python version: %s", sys.version);

#c input params = >paramIn
#jsonStr = paramIn;
jsonStr = '{"xxData": "48656c6c6f20576f726c6421"}'

#to json obj
data = json.loads(jsonStr)

# get hex buff.
hex_data = data['binData']

# get byte array.
byte_data = binascii.unhexlify(hex_data)
ba =  bytearray(byte_data);

# print byte array.
print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
print(byte_data)
ba[0] = 0xff;
ba[1] = 0xff;

# to hex again.
hex_data = binascii.hexlify(ba).decode('utf-8')

# create json obj again.
data = {'binData': hex_data}

# json => str
json_string = json.dumps(data)
fft_result = json_string;
fft_result_len = len(json_string);

# print final output str.
print(json_string)
print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<")

附录D 调用.py文件的 c函数示例

    //python的传入参数部分已经介绍过,不再给出
    //...

    // 调用 Python 函数
    FILE *file = fopen(pyFileFFT, "r");
    if(file!=NULL)
    {
        PyRun_File(file, pyFileFFT, Py_file_input, pDict, pDict);

        //传出参数解析
        PyObject *ro = PyDict_GetItemString(pDict, "fft_result");
        unsigned char *buf = PyByteArray_AsString(ro);
        int len = PyLong_AsLong(PyDict_GetItemString(pDict, "fft_result_len"));
        FFT = cJson_Parse(buf);
    //...

到了这里,关于Linux c 与 python的互操作的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 树莓派PICO入门:电脑连接简易树莓派PICO单片机,烧录,使用python进行简单代码操作。

    需求:pico树莓派一个,python,thonny工具 需求: 1,pico树莓派一个;     2,thonny工具:   通过数据线连接电脑后,桌面会弹出一个文件夹,点击弹出的网络链接到指定网站下载烧录文件,下载完毕后,将烧录文件拖入该文件夹中开始烧录:(注意下载的是mircropython,不要下载

    2024年02月10日
    浏览(41)
  • 单片机/嵌入式小白教程—硬件(三)51单片机最小系统

    目录 简介 51单片机器件原理图 复位电路 供电电路 晶振电路 下载电路 最小系统原理图  更加方便的51单片机 传统51单片机最小系统包含:复位电路、供电电路、晶振电路、下载电路   其中, 第9脚(RST)为复位引脚, 第40脚(VCC)第20脚(GND)为供电引脚, 第19脚(XTAL1)第

    2024年02月08日
    浏览(57)
  • Linux c 与 python的互操作

    注意,上面的是最简单的单向执行代码。代码如果涉及多线程执行,可以使用全局mutex来进行同步。 Python的C API提供了将二进制数据传递给Python脚本的方式。你可以使用PyBytes_FromStringAndSize函数将C/C++中的二进制数据转换为Python的bytes对象,并将其传递给脚本。 事实上,这个参

    2024年02月10日
    浏览(24)
  • 嵌入式(二)单片机基础 | 单片机特点 内部结构 最小系统 电源 晶振 复位

    上一篇文章我们介绍了嵌入式系统 嵌入式系统(Embedded System)是一种特定用途的计算机系统,它通常嵌入在更大的产品或系统中,用于控制、监测或执行特定的任务。这些系统通常由硬件和软件组成,旨在满足特定的需求,如嵌入在家电、汽车、医疗设备、工业自动化、消费

    2024年02月02日
    浏览(89)
  • 嵌入式和单片机

    凡是从事信息技术相关工作的,一定都听说过嵌入式和单片机。 大家都知道,这两个名词,和硬件系统有着非常密切的关系。 但是,如果要问具体什么是嵌入式,什么是单片机,它们之间究竟有什么区别,我相信大部分人并不能解释清楚。 今天,小编就给大家做一个入门科

    2024年02月07日
    浏览(43)
  • 【单片机毕设选题】stm32实现车牌识别系统 -物联网 嵌入式 单片机

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天

    2024年02月20日
    浏览(44)
  • 单片机项目分享 stm32机器视觉的人脸识别系统 - 单片机 物联网 嵌入式

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天

    2024年01月22日
    浏览(59)
  • 单片机项目分享 基于stm32的便携用电功率统计系统 -物联网 嵌入式 单片机

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天

    2024年02月19日
    浏览(76)
  • 7. 嵌入式与单片机

    常见面试题 请说说你对嵌入式的理解。⭐⭐⭐⭐ 嵌入式系统是指以应用为中心,以计算机技术为基础,软件硬件可剪裁,适应应用系统对功能、成本、体积、功耗严格要求的专用计算机系统。 嵌入式系统 主要由 嵌入式微处理器 、 外围硬件设备 、 嵌入式操作系统以及用户

    2024年02月02日
    浏览(53)
  • 单片机项目分享 单片机自动写字机器人设计与实现 - 物联网 嵌入式 stm32

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天

    2024年02月21日
    浏览(72)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包