1. 使用 ctypes(最常用)

基本用法

from ctypes import *

# 加载DLL
mydll = CDLL('mydll.dll')  # Windows
# mydll = CDLL('./libmylib.so')  # Linux

# 调用函数
result = mydll.add(5, 3)
print(f"5 + 3 = {result}")

mydll.hello()

完整示例

from ctypes import *
import os

# 加载DLL
dll_path = os.path.join(os.path.dirname(__file__), 'mydll.dll')
mydll = CDLL(dll_path)

# 指定参数和返回类型(重要!)
mydll.add.argtypes = [c_int, c_int]
mydll.add.restype = c_int

mydll.hello.argtypes = []
mydll.hello.restype = None

# 调用函数
result = mydll.add(10, 20)
print(f"10 + 20 = {result}")

mydll.hello()

2. 处理不同数据类型

基本数据类型

from ctypes import *

mydll = CDLL('mydll.dll')

# 各种C数据类型
mydll.func_int.argtypes = [c_int]
mydll.func_int.restype = c_int

mydll.func_double.argtypes = [c_double]
mydll.func_double.restype = c_double

mydll.func_bool.argtypes = [c_bool]
mydll.func_bool.restype = c_bool

字符串参数

# C函数:void print_string(char* str)
mydll.print_string.argtypes = [c_char_p]
mydll.print_string.restype = None

# 传递字符串
mydll.print_string(b"Hello from Python!")  # 注意使用bytes
mydll.print_string("中文".encode('utf-8'))  # 中文需要编码

指针和数组

# C函数:void process_array(int* arr, int size)
mydll.process_array.argtypes = [POINTER(c_int), c_int]
mydll.process_array.restype = None

# 创建数组
arr = (c_int * 5)(1, 2, 3, 4, 5)
mydll.process_array(arr, 5)

# 读取结果
print(list(arr))

3. 结构体处理

C结构体定义

// point.dll
typedef struct {
    int x;
    int y;
} Point;

__declspec(dllexport) double distance(Point* p1, Point* p2);

Python对应代码

from ctypes import *

# 定义对应的结构体
class Point(Structure):
    _fields_ = [
        ('x', c_int),
        ('y', c_int)
    ]

# 加载DLL
point_dll = CDLL('point.dll')

# 设置函数原型
point_dll.distance.argtypes = [POINTER(Point), POINTER(Point)]
point_dll.distance.restype = c_double

# 创建结构体实例
p1 = Point(10, 20)
p2 = Point(30, 40)

# 调用函数
dist = point_dll.distance(byref(p1), byref(p2))
print(f"Distance: {dist}")

4. 回调函数

C回调函数

// callback.dll
typedef void (*Callback)(int progress);

__declspec(dllexport) void long_operation(Callback callback);

Python回调

from ctypes import *

# 定义回调类型
CALLBACK = CFUNCTYPE(None, c_int)

def progress_callback(progress):
    print(f"Progress: {progress}%")

# 加载DLL
callback_dll = CDLL('callback.dll')
callback_dll.long_operation.argtypes = [CALLBACK]
callback_dll.long_operation.restype = None

# 调用
callback_func = CALLBACK(progress_callback)
callback_dll.long_operation(callback_func)

5. 错误处理

from ctypes import *
import sys

try:
    mydll = CDLL('mydll.dll')
    
    # 检查函数是否存在
    if not hasattr(mydll, 'add'):
        raise AttributeError("Function 'add' not found in DLL")
    
    mydll.add.argtypes = [c_int, c_int]
    mydll.add.restype = c_int
    
    result = mydll.add(5, 3)
    print(f"Result: {result}")
    
except OSError as e:
    print(f"Failed to load DLL: {e}")
except AttributeError as e:
    print(f"Function error: {e}")
except Exception as e:
    print(f"Unexpected error: {e}")

6. 实际示例

C代码(编译为DLL)

// mathlib.c
#include <stdio.h>

__declspec(dllexport) int factorial(int n) {
    if (n <= 1) return 1;
    return n * factorial(n - 1);
}

__declspec(dllexport) void greet(char* name) {
    printf("Hello, %s!\n", name);
}

Python调用

from ctypes import *

# 加载DLL
mathlib = CDLL('./mathlib.dll')

# 设置函数原型
mathlib.factorial.argtypes = [c_int]
mathlib.factorial.restype = c_int

mathlib.greet.argtypes = [c_char_p]
mathlib.greet.restype = None

# 调用
result = mathlib.factorial(5)
print(f"5! = {result}")

mathlib.greet(b"Python User")

7. 其他调用方式

使用 cdll 加载

from ctypes import cdll

# 自动查找DLL
mydll = cdll.mydll  # 在系统路径中的DLL

指定完整路径

from ctypes import CDLL
import os

dll_path = r'C:\full\path\to\your.dll'
mydll = CDLL(dll_path)

总结

  • ctypes 是Python调用DLL的标准方法
  • 必须正确设置 argtypesrestype
  • 注意数据类型转换,特别是字符串
  • 结构体需要使用 Structure 类定义
  • 错误处理很重要,避免程序崩溃

Python调用DLL非常强大,可以让你利用现有的C/C++代码库,同时享受Python的易用性!

参考

https://blog.csdn.net/qq_29630271/article/details/74012465

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐