ctypes 简介

ctypes 简介#

参考资料:

ctypes 是 Python 的外部函数库。它提供了与 C 兼容的数据类型,并允许调用 DLL 或共享库中的函数。可使用该模块以纯 Python 形式对这些库进行封装。

备注

部分示例代码引用了 ctypes c_int 类型。在 sizeof(long) == sizeof(int) 的平台上此类型是 c_long 的别名。所以,在程序输出 c_long 而不是你期望的 c_int 时不必感到迷惑 — 它们实际上是同一种类型。

加载动态链接库#

ctypes 导出了 cdll 对象,在 Windows 系统中还导出了 windlloledll 对象用于载入动态连接库。

您可以通过访问这些对象的属性来加载库。

  • cdll 加载使用标准 cdecl 调用约定导出函数的库

  • windll 库则使用 stdcall 调用约定调用函数

  • oledll 也使用 stdcall 调用约定,并假定函数返回 Windows HRESULT 错误代码。

当函数调用失败时会使用错误代码自动引发 OSError 异常。

备注

cdeclstdcall 是两种不同的函数调用约定,它们定义了函数参数的传递方式、堆栈清理责任以及名称修饰规则。

  1. cdecl(C declaration)

    • 参数传递顺序是从右到左,即最右边的参数最先入栈。

    • 调用者负责清理堆栈(即由函数外部的代码来恢复堆栈指针)。

    • 支持变长参数列表,因此常用于具有可变数量参数的函数,如printf。

    • 在函数名前加上一个下划线作为前缀进行名称修饰(仅在编译时)。

  2. stdcall(Standard call)

    • 参数传递顺序也是从右到左。

    • 被调用的函数负责清理堆栈(即由函数内部的代码来恢复堆栈指针)。

    • 不支持变长参数列表。

    • 在函数名前加上一个下划线作为前缀,并在其后添加一个表示参数字节数的后缀进行名称修饰(仅在编译时)。

两者的联系在于它们都是x86架构上常见的函数调用约定,主要用于Windows平台的软件开发。选择使用哪种调用约定通常取决于特定的编程环境和需求。例如,如果你需要与Windows API进行交互,可能会更倾向于使用stdcall,因为这是Windows API主要使用的调用约定。而cdecl则更常见于GCC编译器中,特别是在UNIX或Linux平台上。

请注意,msvcrt 是包含大多数标准 C 函数的 MS 标准 C 库,并使用 cdecl 调用约定:

>>> from ctypes import *
>>> print(windll.kernel32)  
<WinDLL 'kernel32', handle ... at ...>
>>> print(cdll.msvcrt)      
<CDLL 'msvcrt', handle ... at ...>
>>> libc = cdll.msvcrt      

Windows 会自动添加通常的 .dll 文件扩展名。

备注

通过 cdll.msvcrt 调用的标准 C 函数,可能会导致调用一个过时的,与当前 Python 所不兼容的函数。因此,请尽量使用标准的 Python 函数,而不要使用 msvcrt 模块。

在 Linux 中,要求指定文件名 包括 扩展名来加载库,因此不能使用属性访问的方式来加载库。你应当使用 dll 加载器的 LoadLibrary() 方法,或是应当通过调用构造器创建 CDLL 的实例来加载库:

>>> cdll.LoadLibrary("libc.so.6")  
<CDLL 'libc.so.6', handle ... at ...>
>>> libc = CDLL("libc.so.6")       
>>> libc                           
<CDLL 'libc.so.6', handle ... at ...>