A brief discussion on the use of ctypes

What is ctypes:

  ctypes It is a standard library of Python for interacting with C language. It provides a set of tools and functions that can easily call C functions in dynamic link libraries (DLLs) or shared objects (SOs) and handle conversion of C data types.

To put it simply, ctypes does type conversion between c and python. Since type conversion is done, how to use ctypes to convert types commonly used in c/c++, let’s find out next:

What is a dynamic link library:

  The dynamic link library is a data-function library that has been compiled and can be used directly when the program is running. Different from static link libraries, dynamic link libraries are loaded and linked when the program is running, rather than when compiling. The dynamic link library must be loaded first. For this purpose, ctypes provides three objects: cdll, windll (windows-only), oledll ( windows-only), and makes loading the dll just like accessing the properties of these objects. The three differences are:

(1) cdll: The cdll object loads a function library using the standard cdecl calling convention.

(2) windll: The windll object loads a function library using the stdcall calling convention.

(3) oledll: The oledll object loads a function library using the stdcall calling convention.

Steps for usage:

(1) Load the dynamic link library:

  Use  ctypes the  cdll or  windll (Windows platform) function to load dynamic link libraries or shared objects. You only need to provide the path or name of the library, and ctypes the correct loading function will be automatically selected based on the operating system.

Examples are as follows:


# 示例 1: 加载动态链接库
my_lib = ctypes.CDLL('/path/to/my_lib.so')
 
# 示例 2: 加载共享对象(在 Windows 上)
my_lib = ctypes.windll.LoadLibrary('my_lib.dll')

(2) Get functions in DLL/shared library

my_function = my_lib.my_function # my_function 是动态库中已导出的函数,不导出则不可调用,像访问一个类实例属性一样来载入my_function.argtypes = [ctypes.c_int, ctypes.c_float] my_function.restype = ctypes.c_double # 指定函数的返回类型和参数类型。

(3) Perform type conversion so that it can be passed to the calling c function:  

(1) Basic data types in C language

The use of this part is relatively simple. You can directly use the built-in methods of ctypes to create objects. The methods provided by ctypes and the data types corresponding to the C language are as follows:

ctypes type

C type

Python types

c_bool

_Bool

bool (1)

c_char

char

Single character bytes object

c_wchar

wchar_t

single character string

c_byte

char

int

c_ubyte

unsigned char

int

c_short

short

int

c_ushort

unsigned short

int

c_int

int

int

c_uint

unsigned int

int

c_long

long

int

c_olong

unsigned long

int

c_longlong

__int64 or long long

int

c_ulonglong

unsigned __int64 或 unsigned long long

int

c_size_t

size_t

int

c_ssize_t

ssize_t or  Py_ssize_t

int

c_float

float

float

c_double

double

float

c_longdouble

long double

float

c_char_p

char* (NUL terminated)

bytes object or None

c_wchar_p

wchar_t* (NUL terminated)

string or None

c_void_p

void*

int or None

A few small examples of use:


import ctypes
 
# 加载动态链接库
my_lib = ctypes.CDLL('/path/to/my_lib.so')
 
# 定义函数原型
my_function = my_lib.my_function
my_function.argtypes = [ctypes.c_int]
 
# 转换整型数据类
my_int = 10
my_function(ctypes.c_int(my_int))
 
#转换浮点型数据类型:
my_float = 3.14
my_function(ctypes.c_float(my_float))
 
#转换字符串类型:
my_string = "Hello"
my_function(ctypes.c_char_p(my_string.encode('utf-8')))#转换数组类型:char_array = c_char * 3

(2) Advanced data types in C language

For advanced data types in C language, such as structures, nested structures, structure arrays, structure pointers, etc., ctypes some tools and methods are provided for conversion. Suppose you have a struct type in C code.  MyStruct,Here are a few examples:

import ctypes
 
# 定义 C 结构体类型
class MyStruct(ctypes.Structure):
    _fields_ = [("field1", ctypes.c_int),
                ("field2", ctypes.c_float)]
 
# 加载动态链接库
my_lib = ctypes.CDLL('/path/to/my_lib.so')
 
# 定义函数原型
my_function = my_lib.my_function
my_function.argtypes = [MyStruct]
 
# 创建结构体实例并传递给 C 函数
my_struct = MyStruct()
my_struct.field1 = 10
my_struct.field2 = 3.14
my_function(my_struct)
#转换嵌套结构体
class InnerStruct(ctypes.Structure):
    _fields_ = [("inner_field", ctypes.c_int)] # 定义 C 内部引用结构体class OuterStruct(ctypes.Structure):
    _fields_ = [("outer_field", ctypes.POINTER(InnerStruct))] # 创建结构体实例,并传递给 C 函数
inner = InnerStruct()
inner.inner_field = 10
 
outer = OuterStruct()
outer.outer_field = ctypes.pointer(inner)
 
my_function(ctypes.cast(ctypes.pointer(outer), ctypes.POINTER(OuterStruct)))array_size = 5
my_array = (MyStruct * array_size)()
for i in range(array_size):
    my_array[i].field1 = i
    my_array[i].field2 = float(i)
 
my_function(my_array, array_size)#转换结构体指针和结构体指针数组:#对于结构体指针和结构体指针数组,可以使用 ctypes.POINTER 类型和 ctypes.cast 函数进行转换。# 定义函数原型
my_function = my_lib.my_function
my_function.argtypes = [ctypes.POINTER(MyStruct)]
 
# 创建结构体实例,并传递给 C 函数
my_struct = MyStruct()
my_struct.field1 = 10
my_struct.field2 = 3.14
 
# 传递结构体指针给 C 函数
my_function(ctypes.pointer(my_struct))
 
# 创建结构体指针数组,并传递给 C 函数
array_size = 5
my_array = (ctypes.POINTER(MyStruct) * array_size)()
for i in range(array_size):
    my_array[i] = ctypes.pointer(MyStruct())
     
my_function(ctypes.cast(my_array, ctypes.POINTER(ctypes.POINTER(MyStruct)))) 

(3) Conversion of callback functions in C language

Suppose you have a function in C code  register_callbackthat accepts a function pointer as a parameter and calls that function at the appropriate time. We can  ctypes define a callback function using and pass it to  register_callback.

First, we need to define the type of the callback function and then convert it to a function pointer type. When calling  register_callback , we pass the converted function pointer as argument.

import ctypes
 
# 定义回调函数类型
CallbackFunc = ctypes.CFUNCTYPE(None, ctypes.c_int)
 
# 定义回调函数
def my_callback(value):
    print("Callback called with value:", value)
 
# 加载动态链接库
my_lib = ctypes.CDLL('/path/to/my_lib.so')
 
# 定义函数原型
register_callback = my_lib.register_callback
register_callback.argtypes = [CallbackFunc]
 
# 将 Python 回调函数转换为函数指针
callback_func = CallbackFunc(my_callback)
 
# 注册回调函数
register_callback(callback_func)

First use  ctypes.CFUNCTYPE the defined callback function type  CallbackFunc. Its first parameter is the return type of the callback function, here it is  None, which means there is no return value; the second parameter is the parameter type of the callback function, here it is  ctypes.c_int.

We then defined a callback function in Python  my_callbackthat accepts an integer argument and prints the value of that argument inside the function.

Next, we  CallbackFunc convert the Python callback function to a function pointer type  using callback_func.

Finally, we load the dynamic link library and call  register_callback the function, passing the converted function pointer as a parameter to the C function.


 How to obtain information

【Message 777】

Friends who want to get the source code and other tutorial materials, please like + comment + collect , three times in a row!

After three consecutive rounds , I will send you private messages one by one in the comment area~

Guess you like

Origin blog.csdn.net/GDYY3721/article/details/132210265