Python - ctypes - 如何调用函数和访问结构字段?
我有一个C语言的库:
smart_string.h:
typedef struct SmartString {
unsigned string_len;
unsigned alloc_len;
char *str;
char *str_terminator;
} SmartString;
SmartString *SmartString_new(char *str);
... definitions of more functions ...
它的实现代码在一个叫smart_string.c的文件里。
我需要一个指南,教我怎么运行SmartString_new()
这个函数,以及如何访问返回的结构体指针里的字段。
有没有人能教我一下?
谢谢!
1 个回答
8
我来给自己解答一下,并和大家分享一下知识:
首先,需要从C文件创建一个共享库:
gcc -shared -fpic smart_string.c -o SmartString.so
然后,使用下面的Python代码(代码中的注释会解释每一步的操作):
注意:上面API中的char*
是C语言中可以修改的字符串,而const char*
是只读字符串。因为C语言的API需要char*
而不是const char*
,所以我们必须传递一个可变字符串,这样C代码才能对它进行修改。Python中的字符串默认是不可变的。因此,我们在这里使用create_string_buffer()
这个函数。
python_smart_string.py:
import ctypes
from ctypes import *
# Defining the python type that represents the C SmartString
# It must extend the 'Structure' class
# Structure, c_uint, c_char_p, etc. were imported from ctypes
class SmartString(Structure):
_fields_=[("string_len",c_uint),
("alloc_len",c_uint),
("str",c_char_p),
("str_terminator", c_char_p)]
# Loading the C shared lib I've just compiled
smartstring_lib = ctypes.CDLL('SmartString.so')
# Defining pointer to the SmartString_new() function
SmartString_new = smartstring_lib.SmartString_new
# Declaring the function return type - a pointer to a SmartString object - just like in the C code
SmartString_new.restype = POINTER(SmartString)
# Declaring list of parameter types. In this case, the list contains only one item,
# as the function has only one parameter
SmartString_new.argtypes = [c_char_p]
# Calling the SmartString_new() function. Expecting to get a pointer to SmartString object into 'my_str'
# The API requires a MUTABLE string, so create_string_buffer() is used here
# The reference to this string is not saved, as I don't care if it is modified by the C code
my_str = SmartString_new(create_string_buffer('my nice string'))
# Printing fields of the dereferenced returned value (dereferencing is done using '.contents')
print my_str.contents.string_len
print my_str.contents.alloc_len
print my_str.contents.str
print my_str.contents.str_terminator