其实python和c混合调用的方法很多,如swig、cpython等等,但这些都不是标准库,需要额外安装的,本文讲的是标准库的ctypes来调用c,实现强大的功能,没办法霸道C\C++就是那么强大,不服不行,有那种语言是无法调用C的,没有吧。
本文既不是扫盲也不是hello,world之类的,期初我百度了python通过ctypes封装调用c,全是千万一律的,一段基础代码拷贝了无数次,所以这次搞全面的,直接封装,当然本人也刚接触python语言半月,诸多的东西还不太会用,写的不好还请见谅。
在了解ctypes之前,请一定记住上图,ctypes基础类型(其实就是C基础类型)和python基础类型的映射,基础类型太重要了,再复杂的代码也是由基础类型构成的,另外补充一点,你有没有发现上面似乎少了枚举Enum,对的,就是少了枚举,其实枚举就是整形int,有些语言当然也可以指定其他类型,枚举就是一个基础类型(如int)可取值的集合,每次用的就里面一个值而已,所以本文的代码枚举都用int,枚举在c中还是用的挺多的
ctypes调用c或c++只能以动态库的形式调用,而且必须是动态库导出的函数才可以。ctypes导出了 cdll,在windows上还有 windll 和 oledll 对象用于载入动态链接库。
载入动态链接库可以直接存取其属性。 cdll 载入导出函数符合cdecl调用规范的库,而 windll 载入导出函数符合 stdcall 调用规范的库, oledll 也使用 stdcall 调用规范,并假设函数返回Windows的HRESULT错误码。错误码用于在出错时自动抛出WindowsError这个Python异常。
注意win32系统动态链接库,如kernel32和user32经常同时导出ANSI和UNICODE版本的函数。UNICODE版本的会在名字末尾加"W",而ANSI版本的加上"A"。Win32版本的 GetModuleHandle 函数,返回给定模块名的句柄,有如下C原型,还有一个宏用于暴露其中一个作为 GetModuleHandle ,依赖于UNICODE定义与否。
文字和代码都比较多,贴上要点吧
1.ctypes中的枚举Enum类型其实就是int
//C 默认0开始
enum Sex {
Boy,
Girl,
};
python可以多种方式定义,如全局变量,class等,还是用Enum吧
from enum import Enum, unique
@unique
class Sex(Enum):
Boy=0
Girl=1
是不是简单,带上@unique是python修饰符,让值唯一的功能
2.ctypes多级指针(指向指针的指针)
**int,别懵,既然*int 在ctypes中为 POINTER(c_int),那么想当然**int就是 POINTER(POINTER(c_int)),括号可别打错了,有几级就嵌套几个POINTER()
3.结构体内嵌或者在结构内含有自己的引用(如函数指针传递的参数就是结构体自身指针)
struct SoundIo {
void *userdata;
void (*on_devices_change)(struct SoundIo *);
void (*on_backend_disconnect)(struct SoundIo *, int err);
void (*on_events_signal)(struct SoundIo *);
enum SoundIoBackend current_backend;
const char *app_name;
void (*emit_rtp