python调用C语言动态链接库详解

本文详细介绍了在Linux环境下,如何使用Python的ctypes库调用C编写的动态链接库,包括基础调用、结构体操作和回调函数的实战。还探讨了遇到的回调函数并发问题及其解决方案。
部署运行你感兴趣的模型镜像


本文介绍在linux环境下python调用c语言编写的动态链接库so。

Python 调用动态链接库

  • linux操作系统中动态链接库为so文件。
  • python调用so文件使用动态方式加载,python中使用ctypes库
  • ctypes是Python调用c的动态链接库的一个内置模块。

环境说明

  • 操作系统:linux
  • python: python3

构建动态链接库

  • 项目结构
├── CMakeLists.txt  	# cmake构建配置文件
├── hello.cc			# 动态链接库源文件
└── hello.h			# 动态链接库头文件
  • CMakeLists.txt
cmake_minimum_required(VERSION 3.1)		# 设置cmake最小版本
project(hello)					# 设置项目名称
set(src_h hello.h)				# 设置头文件
set(src_c hello.c)				# 设置源文件
add_library( hello SHARED ${src_h} ${src_c})	# 生成libhello.so库文件。
  • hello.h
#ifdef __cplusplus
extern "C"{
#endif

#ifndef _HELLO_H_
#define _HELLO_H_

// -------------- so基础调用 -------------
void say_hello();				// 基础调用,无参数调用
void say_hello2(int iNum);			// 传递int类型参数
void say_hello3(const char *str);		// 传递char * 字符串
int  say_hello4(int iNum1,int Num2);		// 传递两个参数,并且带返回值。

// -------------- so结构体调用 -------------
struct POINT{
	int x;
	int y;
};
struct POINT get_mouse_position();		// 返回结构体
struct POINT *get_position();			// 返回结构体指针
void release_point(struct POINT * ptrData);	// 将结构指针作为参数

// -------------- so 回调函数 -------------
typedef void (callback)();
typedef int (callback2)(int);
void send_message(int a, callback funcPtr);	// 无参数的回调函数
int send_message2(int a, callback2 funcPtr);	// 带参数,带返回值的回调函数

#ifdef __cplusplus
}
#endif
#endif
  • hello.c
#include <stdio.h>
#include <stdlib.h>
#include "hello.h"
void say_hello(){
    printf("hello\r\n");
}

void say_hello2(int iNum){
    printf("hello2 num:%d\r\n",iNum);
}

void say_hello3(const char *str){
    printf("hello3 str:%s\r\n",str);
}

int  say_hello4(int iNum1,int iNum2){
    int res = iNum1 + iNum2;
    printf("hello4 res:%d\r\n",res);
    return res;
}
struct POINT get_mouse_position(){
   struct POINT temp;
    temp.x = 12;
    temp.y = 13;
    return temp;
}
struct POINT *get_position(){
   struct  POINT *temp =NULL;
    temp = (struct POINT *)malloc(sizeof(struct POINT));
    temp->x = 10;
    temp->y = 20;
    return temp;
}

void release_point(struct POINT * ptrData){
    if(NULL != ptrData){
        free(ptrData);
        ptrData = NULL;   
    }
}
void send_message(int a, callback  funcPtr){
    printf("send_message a:%d\r\n",a);
    if(funcPtr != NULL)
    funcPtr();
}


int send_message2(int a, callback2 funcPtr){
    printf("send_message2 a:%d\r\n",a);
    if(funcPtr != NULL){
        int res= funcPtr(6);
        printf("回调函数的执行结果为:%d\r\n",res);
    }
    return 5;
}

  • 构建步骤,如果生成libhello.so文件那么就构建成功了
mkdir build
cd build
cmake ..
make

python动态链接库基础调用

将so文件拷贝到py文件的同级目录
运行命令:

python3 main.py

目录结构如下:

├── libhello.so
└── main.py

main.py

import ctypes
from ctypes import *
solib =  ctypes.CDLL('./libhello.so')

func_say_hello = solib.say_hello
func_say_hello()
print("func_say_hello 执行完毕!")
print("============================")

func_say_hello2 = solib.say_hello2
func_say_hello2(2)
print("func_say_hello2 执行完毕!")
print("============================")

func_say_hello3 = solib.say_hello3
str = "I love you"
func_say_hello3(str.encode("UTF-8"))
print("func_say_hello3 执行完毕!")
print("============================")

func_say_hello4 = solib.say_hello4
res = func_say_hello4(5,6)
print("func_say_hello3 执行完毕!结果为:",res)
print("============================")

执行结果如下:

hello
func_say_hello 执行完毕!
============================
hello2 2
func_say_hello2 执行完毕!
============================
hello3 I love you
func_say_hello3 执行完毕!
============================
hello4 11
func_say_hello3 执行完毕!结果为: 11
============================

python动态链接库结构体调用

main.py

import ctypes
from ctypes import *

class PyPointStruct(Structure):
    _fields_ = [
        ("x", c_int),
        ("y", c_int),
    ]

solib =  ctypes.CDLL('./libhello.so')

func_get_mouse_position = solib.get_mouse_position
func_get_mouse_position.restype = PyPointStruct # 设置函数返回结果的类型为结构体
resp = func_get_mouse_position()
print("res2:",resp.x)
print("res2:",resp.y)
print("============================")

func_get_position = solib.get_position
func_get_position.restype = POINTER(PyPointStruct) # 设置函数返回结果的类型为结构体指针
resb = func_get_position()
print("res3:",resb.contents.x)
print("res3:",resb.contents.y)
print("============================")

执行结果如下:

res2: 12
res2: 13
============================
res3: 10
res3: 20
============================

python动态链接库回调函数

main.py

import ctypes
from ctypes import *

solib =  ctypes.CDLL('./libhello.so') 	# 加载动态链接库

def cb_sayhello():						# 无参数的回调函数
    print("python hello")

def cb_sayhello2(res):					# 带参数有返回值的回调函数。
    print("python hello2,res:",res)
    return 1024


solib =  ctypes.CDLL('./libhello.so')   

func_send_message = solib.send_message
# CFUNCTYPE定义方法的签名,第一参数表示方法的返回类型,后面开始编译参数的类型
funcStruct =  CFUNCTYPE(None)			
solib.send_message(10,funcStruct(cb_sayhello))
print("============================")

send_message2 = solib.send_message2
# CFUNCTYPE定义方法的签名,第一参数表示方法的返回值,后面开始编译参数的类型
funcStruct2 =  CFUNCTYPE(c_int,c_int)
send_message2(10,funcStruct2(cb_sayhello2))
print("============================")

执行结果:

send_message a:10
python hello
============================
send_message2 a:10
python hello2,res: 6
回调函数的执行结果为:1024
============================

Note:在一个项目中,我使用python调用动态库,发现奔溃的现象。
具体问题如下,
我将python中的回调函数传递给so调用,但是so的程序中使用了多线程调用回调函数,由于python的回调函数时通过构造对象的方式调的send_message2(10,funcStruct2(cb_sayhello2)) 其中,funcStruct2(cb_sayhello2)是一个对象,因此在这个函数执行完成后会释放这个对象,在so的程序中多线程函数执行回调函数对象就已经被释放了 ,因此照成回调函数调用崩溃的情况。

代码下载地址
https://download.csdn.net/download/arv002/33253778

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三雷科技

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值