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 |
---|---|---|
_Bool |
bool (1) |
|
char |
Single character bytes object |
|
|
single character string |
|
char |
int |
|
unsigned char |
int |
|
short |
int |
|
unsigned short |
int |
|
int |
int |
|
unsigned int |
int |
|
long |
int |
|
unsigned long |
int |
|
__int64 or long long |
int |
|
unsigned __int64 或 unsigned long long |
int |
|
|
int |
|
|
int |
|
float |
float |
|
double |
float |
|
long double |
float |
|
char* (NUL terminated) |
bytes object or |
|
wchar_t* (NUL terminated) |
string or |
|
void* |
int or |
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_callback
that 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_callback
that 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~