2023-01-18 python ctypes 引用 dll 动态连接库调用C函数
创始人
2024-05-13 13:47:46
0

python ctypes 引用 dll 动态连接库调用C函数

  • 前言
  • 一、ctypes 是什么?
  • 二、ctypes 使用上的一些问题
  • 总结


前言

python是典型的胶水语言, 有优雅的代码, C语言是典型的底层语言, 有极强的效率, 所以当涉及运算密集型项目, 可以用 python + C 的形式解决.

python 有标准的 ctypes 模块, 专门进行与 C 或 C++ 封装的 dll 动态连接库, 使用不难, 但有些坑还是要避一避.


一、ctypes 是什么?

ctypes 是 python 的自带模块, 用于连接 dll 文件, 从而使得 python 利用 C 语言高性能计算的性质.

通过 CDLL 或 WinDLL连接dll文件: 当cdll为小写时需要用到LoadLibrary, 如果为大写CDLL或WinDLL则直接引用即可.

import ctypes# 引入dll
lib = ctypes.cdll.LoadLibrary('./answer/test179.dll')lib2 = ctypes.WinDLL('./answer/test179.dll')

ctypes 可以设置结构, 对应C语言中的结构:同时从ctypes有C语言对应的数据类型.

# 设置结构
class Test(ctypes.Structure):_fields_ = [('a', ctypes.c_int),('b', ctypes.c_int),('c', ctypes.c_char*10),('d', ctypes.c_char*10)]

通过获取函数指针, 设置函数形参和返回类型进行函数调用:

# 获取函数指针
fun = lib.ConstructTest# 设置形参类型
fun.argtypes = (ctypes.c_int, ctypes.c_int, ctypes.c_char_p, ctypes.c_char_p)
# 设置函数返回值
fun.restype = Test# 测试函数
tst = fun(1, 1, ctypes.create_string_buffer(b'abc'), ctypes.create_string_buffer(b'bbb'))

二、ctypes 使用上的一些问题

对于字符串, python和C语言的差别还是不小, 对于中文, python是可以无障碍的输出, 但调用dll输出中文, 那就是灾难.

在Windows下, 用utf8编码的dll需要另辟蹊径.

print('中文') # 对于python没有问题url = ctypes.create_string_buffer("中文.go.com".encode('gbk'))  # 不可以用.encode('utf-8')
username = '汉字'.encode('gbk')  # 不可用.encode('utf-8')

对于C的char数组, python使用的是 c_char * 5 这种形式.

在CSDN的问答中, 有个关于 ctypes 调用函数返回 WindowsError: exception: access violation reading 0x00000000

发现连接库, 设置函数传参等都没有问题, 在StackOverflow出现过类似问题, 发现是 32 位 python 调用 64 位 dll 文件, 可以想见, 传参和返回值基本都是错的,

因为在C语言, 32位系统的基本数据类型和64位系统的基本数类型占用内存不一致, int在32位系统一般位 2 字节, 而64位系统是4字节, 指针32位系统是4字节, 如错误中 0x00000000 明显是四字节, 但64位系统, 指针一般为8字节,

无论传入参数还是传出返回值, 根本就对不上号, 所以读取的内存完全不是一回事, 直接返回错误. 当然, C语言确实不以兼容性见长.

以下是代码, CPP文件以注释形式给出:

# test178.h
# #ifndef TEST
# #define TEST
# #include 
#
# #ifdef BUILD_DLL
# #define DLL_EXPORT __declspec(dllexport)
# #else
# #define DLL_EXPORT __declspec(dllimport)
#
# #endif
#
# #ifdef __cplusplus
# extern "C"
# {
# #endif
#
#     typedef struct
#     {
#         int a;
#         int b;
#         char c[10];
#         char d[10];
#     } Test;
#
#     DLL_EXPORT auto ConstructTest(int aa, int bb, const char *cc,
#                                   const char *dd) -> Test;
#
#     DLL_EXPORT void print(Test tst);
#
# #ifdef __cplusplus
# }
# #endif
#
# #endif# test179.cpp
# #define BUILD_DLL
#
# #include "test178.h"
# #include 
#
# DLL_EXPORT auto ConstructTest(int aa, int bb, const char *cc, const char *dd)
#     -> Test
# {
#     Test tst;
#     tst.a = aa;
#     tst.b = bb;
#     strcpy(tst.c, cc);
#     strcpy(tst.d, dd);
#     return tst;
# }
#
# DLL_EXPORT void print(Test tst)
# {
#     // printf("%d-%d-%s", tst.a, tst.b, tst.c);
#     printf("%d-%d-%s-%s\n", tst.a, tst.b, tst.c, tst.d);
# }
#
# // int main()
# //{
# //     print(ConstructTest(1, 1, "dsdjl"));
# //     return 0;
# // }# 引入ctypes模块
import ctypes# 引入dll
lib = ctypes.cdll.LoadLibrary('./answer/test179.dll')lib2 = ctypes.WinDLL('./answer/test179.dll')# 设置结构
class Test(ctypes.Structure):_fields_ = [('a', ctypes.c_int),('b', ctypes.c_int),('c', ctypes.c_char*10),('d', ctypes.c_char*10)]# 获取函数指针
fun = lib.ConstructTest# 设置形参类型
fun.argtypes = (ctypes.c_int, ctypes.c_int, ctypes.c_char_p, ctypes.c_char_p)
# 设置函数返回值
fun.restype = Test# 测试函数
tst = fun(1, 1, ctypes.create_string_buffer(b'abc'), ctypes.create_string_buffer(b'bbb'))# 测试结构
tst2 = Test(1, 1, b'abc', b'aaa')# 打印函数返回值
lib.print(tst)
# 打印结构返回值
lib.print(tst2)tst3 = fun(1, 1, b'abc', b'bbb')
lib.print(tst3)tst4 = fun(1, 1, '中文'.encode('gbk'), '汉字'.encode('gbk'))
lib.print(tst4)

Cpp代码编译参数:

 E:\msys64\clang64\bin\clang++.exe -shared -std=c++17 test179.cpp -o e:\clangC++\answer\C++\test179.dll 

总结

有人用 python + C 可以高效完成各种功能代码, 具备python的优雅, C的高效, 不过还是有些坑需要注意.

相关内容

热门资讯

电视安卓系统哪个品牌好,哪家品... 你有没有想过,家里的电视是不是该升级换代了呢?现在市面上电视品牌琳琅满目,各种操作系统也是让人眼花缭...
安卓会员管理系统怎么用,提升服... 你有没有想过,手机里那些你爱不释手的APP,背后其实有个强大的会员管理系统在默默支持呢?没错,就是那...
安卓系统软件使用技巧,解锁软件... 你有没有发现,用安卓手机的时候,总有一些小技巧能让你玩得更溜?别小看了这些小细节,它们可是能让你的手...
安卓系统提示音替换 你知道吗?手机里那个时不时响起的提示音,有时候真的能让人心情大好,有时候又让人抓狂不已。今天,就让我...
安卓开机不了系统更新 手机突然开不了机,系统更新还卡在那里,这可真是让人头疼的问题啊!你是不是也遇到了这种情况?别急,今天...
安卓系统中微信视频,安卓系统下... 你有没有发现,现在用手机聊天,视频通话简直成了标配!尤其是咱们安卓系统的小伙伴们,微信视频功能更是用...
安卓系统是服务器,服务器端的智... 你知道吗?在科技的世界里,安卓系统可是个超级明星呢!它不仅仅是个手机操作系统,竟然还能成为服务器的得...
pc电脑安卓系统下载软件,轻松... 你有没有想过,你的PC电脑上安装了安卓系统,是不是瞬间觉得世界都大不一样了呢?没错,就是那种“一机在...
电影院购票系统安卓,便捷观影新... 你有没有想过,在繁忙的生活中,一部好电影就像是一剂强心针,能瞬间让你放松心情?而我今天要和你分享的,...
安卓系统可以写程序? 你有没有想过,安卓系统竟然也能写程序呢?没错,你没听错!这个我们日常使用的智能手机操作系统,竟然有着...
安卓系统架构书籍推荐,权威书籍... 你有没有想过,想要深入了解安卓系统架构,却不知道从何下手?别急,今天我就要给你推荐几本超级实用的书籍...
安卓系统看到的炸弹,技术解析与... 安卓系统看到的炸弹——揭秘手机中的隐形威胁在数字化时代,智能手机已经成为我们生活中不可或缺的一部分。...
鸿蒙系统有安卓文件,畅享多平台... 你知道吗?最近在科技圈里,有个大新闻可是闹得沸沸扬扬的,那就是鸿蒙系统竟然有了安卓文件!是不是觉得有...
宝马安卓车机系统切换,驾驭未来... 你有没有发现,现在的汽车越来越智能了?尤其是那些豪华品牌,比如宝马,它们的内饰里那个大屏幕,简直就像...
p30退回安卓系统 你有没有听说最近P30的用户们都在忙活一件大事?没错,就是他们的手机要退回安卓系统啦!这可不是一个简...
oppoa57安卓原生系统,原... 你有没有发现,最近OPPO A57这款手机在安卓原生系统上的表现真是让人眼前一亮呢?今天,就让我带你...
安卓系统输入法联想,安卓系统输... 你有没有发现,手机上的输入法真的是个神奇的小助手呢?尤其是安卓系统的输入法,简直就是智能生活的点睛之...
怎么进入安卓刷机系统,安卓刷机... 亲爱的手机控们,你是否曾对安卓手机的刷机系统充满好奇?想要解锁手机潜能,体验全新的系统魅力?别急,今...
安卓系统程序有病毒 你知道吗?在这个数字化时代,手机已经成了我们生活中不可或缺的好伙伴。但是,你知道吗?即使是安卓系统,...
奥迪中控安卓系统下载,畅享智能... 你有没有发现,现在汽车的中控系统越来越智能了?尤其是奥迪这种豪华品牌,他们的中控系统简直就是科技与艺...